@xenon-device-management/xenon 2.14.0 → 2.15.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 (259) hide show
  1. package/README.md +7 -4
  2. package/lib/package.json +5 -5
  3. package/lib/public/assets/{AnnotationOverlay-B_VNtKBH.js → AnnotationOverlay-Btq3dZRI.js} +1 -1
  4. package/lib/public/assets/{ApiKeyGate-BwuaMjkX.js → ApiKeyGate-C9OoAgg_.js} +1 -1
  5. package/lib/public/assets/DeviceMosaicView-DBC_xczB.js +2 -0
  6. package/lib/public/assets/{EmptyState-BSjhk_IV.js → EmptyState-DqWU2-vM.js} +1 -1
  7. package/lib/public/assets/{FieldGroup-Cb5QZsE1.js → FieldGroup-CveQ3xrA.js} +1 -1
  8. package/lib/public/assets/{FilterMenu-BAaSlWbW.js → FilterMenu-BfKDSfHz.js} +1 -1
  9. package/lib/public/assets/{Menu-JGGYrSQQ.js → Menu-CtdCybzA.js} +1 -1
  10. package/lib/public/assets/{Modal-CFCp3n9d.js → Modal-Bsvj1tm2.js} +1 -1
  11. package/lib/public/assets/{RecordingPage-CbJj_EBT.js → RecordingPage-CRofOiyx.js} +1 -1
  12. package/lib/public/assets/{RecordingsPage-BJeYnygR.js → RecordingsPage-jNQHb2IR.js} +1 -1
  13. package/lib/public/assets/{SegmentedControl-Bg42Atjy.js → SegmentedControl-C8HtTha-.js} +1 -1
  14. package/lib/public/assets/{SettingCard-Njz1pUIJ.js → SettingCard-D8K1LZNo.js} +1 -1
  15. package/lib/public/assets/{Table-BcTm5xV2.js → Table-zNTX92Pn.js} +1 -1
  16. package/lib/public/assets/{activity-DOVdsfMQ.js → activity-CJ8LwZq9.js} +1 -1
  17. package/lib/public/assets/ai-settings-CgxQZqrc.js +16 -0
  18. package/lib/public/assets/{api-keys-BKnNSTw9.js → api-keys-ECpo-zTo.js} +1 -1
  19. package/lib/public/assets/{apps-D0SC6uw6.js → apps-BjGymyf3.js} +1 -1
  20. package/lib/public/assets/{arrow-left-MMbTmgoE.js → arrow-left-BWfCbeHP.js} +1 -1
  21. package/lib/public/assets/{arrow-right-BMfnGmxW.js → arrow-right-DC7UGf_n.js} +1 -1
  22. package/lib/public/assets/{arrow-up-right-DuAftMWB.js → arrow-up-right-BOjwybDk.js} +1 -1
  23. package/lib/public/assets/{auth-shell-nZC2JNDO.js → auth-shell-CxMTo9aH.js} +2 -2
  24. package/lib/public/assets/{builds-page-hDCgTwkS.js → builds-page-DOCm4HkA.js} +1 -1
  25. package/lib/public/assets/{button-Dda4irn_.js → button-Cg08-EMT.js} +1 -1
  26. package/lib/public/assets/{calendar-BMr0Q62v.js → calendar-CA1ikLJs.js} +1 -1
  27. package/lib/public/assets/{check-CZ9iw9-e.js → check-BMTaH72W.js} +1 -1
  28. package/lib/public/assets/{chevron-right-BRYJJVC9.js → chevron-right-B2QOv9Nx.js} +1 -1
  29. package/lib/public/assets/{circle-check-CqAJjQ5O.js → circle-check-CYXBoUqT.js} +1 -1
  30. package/lib/public/assets/{circle-x-DlDJtnVz.js → circle-x-DTwnSAnl.js} +1 -1
  31. package/lib/public/assets/{clock-CpuDKysU.js → clock-C8_HViQP.js} +1 -1
  32. package/lib/public/assets/{copy-CAQydNFe.js → copy-Be7LNMXV.js} +1 -1
  33. package/lib/public/assets/derive-UnLRp4r3.js +1 -0
  34. package/lib/public/assets/device-explorer-BOqtfGXz.js +282 -0
  35. package/lib/public/assets/{download-C9XG6lLv.js → download-B56lwxWP.js} +1 -1
  36. package/lib/public/assets/forgot-password-CCU6bzLn.js +1 -0
  37. package/lib/public/assets/{h264Stream-VQBphYhg.js → h264Stream-C-OtmIuk.js} +6 -6
  38. package/lib/public/assets/index-B9KQ6LsY.js +15 -0
  39. package/lib/public/assets/{index-BbKEXUFH.js → index-BOxe43p1.js} +2 -2
  40. package/lib/public/assets/{index-DJGc1M2f.js → index-CfxsUslp.js} +1 -1
  41. package/lib/public/assets/{input-Cm0tmSoc.js → input-CZHFjbSg.js} +1 -1
  42. package/lib/public/assets/{line-chart-D2DyJCml.js → line-chart-Gl_Dz3X_.js} +1 -1
  43. package/lib/public/assets/{list-checks-UWf1GY99.js → list-checks-CCgjeyGY.js} +1 -1
  44. package/lib/public/assets/{lock-CCJv9m_I.js → lock-CkOwgDcx.js} +1 -1
  45. package/lib/public/assets/{login-f8vOVW-U.js → login-D5cc4w7M.js} +1 -1
  46. package/lib/public/assets/{maintenance-settings-C1PrkuAH.js → maintenance-settings-t7qr3fvX.js} +1 -1
  47. package/lib/public/assets/{monitor-B2jDgwm7.js → monitor-DEJixKQO.js} +1 -1
  48. package/lib/public/assets/{mouse-pointer-2-DLI1RtzU.js → mouse-pointer-2-CtOrk4M8.js} +1 -1
  49. package/lib/public/assets/{network-ebT86qoi.js → network-Dii9qdvk.js} +1 -1
  50. package/lib/public/assets/{overview-C0aykVrd.js → overview-rolAACrO.js} +1 -1
  51. package/lib/public/assets/{page-header-BjzgWz-T.js → page-header-COQZxJfR.js} +1 -1
  52. package/lib/public/assets/{play-DLG9t8FU.js → play-DrN1Se_R.js} +1 -1
  53. package/lib/public/assets/{plus-nBFSMu_X.js → plus-5aq-9uRx.js} +1 -1
  54. package/lib/public/assets/{profile-page-CSl0UYlv.js → profile-page-6i5kY6kF.js} +1 -1
  55. package/lib/public/assets/{reset-password-LeOuHqmB.js → reset-password-sp2IBrc7.js} +1 -1
  56. package/lib/public/assets/runbook-page-DJDjeopU.js +253 -0
  57. package/lib/public/assets/{select-88jHcl-Z.js → select-Bpyn7rWO.js} +1 -1
  58. package/lib/public/assets/{selector-detail-redirect-BbXKJjZM.js → selector-detail-redirect-BH74vmKv.js} +1 -1
  59. package/lib/public/assets/{selector-health-page-B4rA1Xkv.js → selector-health-page-Cw_g218H.js} +1 -1
  60. package/lib/public/assets/session-detail-page-AZJE6XXE.js +4 -0
  61. package/lib/public/assets/{settings-GF6ZMSQ6.js → settings-C3uyGhyc.js} +1 -1
  62. package/lib/public/assets/{settings-Dep_3kbA.css → settings-K8UHWMdI.css} +1 -1
  63. package/lib/public/assets/{stat-tile-BV98e_Sv.js → stat-tile-xVqAKIlI.js} +1 -1
  64. package/lib/public/assets/{tablet-BiAsnFDj.js → tablet-BxUScAeO.js} +1 -1
  65. package/lib/public/assets/{teams-B4-jrr-1.js → teams-B5ljGkY2.js} +1 -1
  66. package/lib/public/assets/{trash-2-C5RSuX0e.js → trash-2-B701i8sy.js} +1 -1
  67. package/lib/public/assets/{upload-BG7_rMXK.js → upload-C2gr44RS.js} +1 -1
  68. package/lib/public/assets/{use-builds-data-J-riQYyC.js → use-builds-data-NeQOFEoy.js} +1 -1
  69. package/lib/public/assets/{use-password-reset-mode-C8-eH-UG.js → use-password-reset-mode-DEzJq5ef.js} +1 -1
  70. package/lib/public/assets/{users-CFba5TSy.js → users-D_vv_yz4.js} +1 -1
  71. package/lib/public/assets/{users-Cp0beJm3.js → users-MY6eNe6s.js} +1 -1
  72. package/lib/public/assets/{video-off-DDsEISjV.js → video-off-OK1lNZQn.js} +1 -1
  73. package/lib/public/assets/{webhook-settings-BGu32vSB.js → webhook-settings-BU-C9lBf.js} +1 -1
  74. package/lib/public/assets/{zap-l4VaXzq8.js → zap-DO9ry1iz.js} +1 -1
  75. package/lib/public/index.html +1 -1
  76. package/lib/schema.json +5 -5
  77. package/lib/src/app/dashboardPluginLink.js +117 -0
  78. package/lib/src/app/index.js +13 -34
  79. package/lib/src/app/openapi/control.yaml +6 -4
  80. package/lib/src/app/openapi/grid.yaml +8 -2
  81. package/lib/src/app/openapi/identity.yaml +103 -31
  82. package/lib/src/app/openapi/platform.yaml +33 -15
  83. package/lib/src/app/openapi/sessions.yaml +10 -3
  84. package/lib/src/app/routers/apikeys.js +14 -2
  85. package/lib/src/app/routers/auth.js +29 -5
  86. package/lib/src/app/routers/control.js +13 -5
  87. package/lib/src/app/routers/dashboard.js +42 -27
  88. package/lib/src/app/routers/grid.js +5 -3
  89. package/lib/src/app/routers/profile.js +21 -0
  90. package/lib/src/app/routers/users.js +10 -5
  91. package/lib/src/app/swagger.js +2 -0
  92. package/lib/src/app/ws/h264StreamWs.js +10 -1
  93. package/lib/src/config.js +1 -0
  94. package/lib/src/dashboard/commands.js +5 -5
  95. package/lib/src/dashboard/event-manager.js +49 -61
  96. package/lib/src/dashboard/services/failure-analysis-service.js +136 -45
  97. package/lib/src/dashboard/sessionCommandSummary.js +39 -0
  98. package/lib/src/data-service/device-store.js +14 -1
  99. package/lib/src/data-service/prisma-store.js +19 -7
  100. package/lib/src/data-service/web-config-service.js +7 -0
  101. package/lib/src/device-managers/android/AndroidH264StreamService.js +69 -20
  102. package/lib/src/device-managers/android/H264Multiplexer.js +38 -4
  103. package/lib/src/device-utils.js +20 -2
  104. package/lib/src/gateway/defaultGateway.js +1 -1
  105. package/lib/src/gateway/forwardToNode.js +2 -0
  106. package/lib/src/gateway/healReport.js +87 -0
  107. package/lib/src/gateway/sessionGateway.js +12 -2
  108. package/lib/src/generated/client/edge.js +4 -3
  109. package/lib/src/generated/client/index-browser.js +1 -0
  110. package/lib/src/generated/client/index.d.ts +32 -0
  111. package/lib/src/generated/client/index.js +4 -3
  112. package/lib/src/generated/client/package.json +1 -1
  113. package/lib/src/generated/client/schema.prisma +3 -0
  114. package/lib/src/generated/client/wasm.js +1 -0
  115. package/lib/src/interceptors/CommandInterceptor.js +243 -181
  116. package/lib/src/middleware/authMiddleware.js +15 -3
  117. package/lib/src/middleware/commandCaller.js +3 -3
  118. package/lib/src/middleware/verifyCredential.js +58 -1
  119. package/lib/src/plugin.js +8 -3
  120. package/lib/src/services/AICommandService.js +9 -2
  121. package/lib/src/services/AIService.js +192 -42
  122. package/lib/src/services/EmailService.js +29 -0
  123. package/lib/src/services/OrphanSweeper.js +2 -0
  124. package/lib/src/services/SelectorVerificationJob.js +15 -4
  125. package/lib/src/services/ServerManager.js +11 -1
  126. package/lib/src/services/SessionLifecycleService.js +86 -26
  127. package/lib/src/services/SocketServer.js +19 -3
  128. package/lib/src/services/bug-report/video-slice.js +4 -1
  129. package/lib/src/services/device-access/leaseOverride.js +7 -5
  130. package/lib/src/services/healing/FuzzyXmlHealingProvider.js +51 -0
  131. package/lib/src/services/healing/HealEtalonService.js +3 -2
  132. package/lib/src/services/healing/HealingOrchestrator.js +55 -72
  133. package/lib/src/services/healing/OcrHealingProvider.js +41 -64
  134. package/lib/src/services/healing/ResilioTreeHealingProvider.js +41 -50
  135. package/lib/src/services/healing/VisualAiHealingProvider.js +1 -1
  136. package/lib/src/services/healing/fingerprintIdentity.js +126 -0
  137. package/lib/src/services/healing/resilioPath.js +274 -0
  138. package/lib/src/services/logcat/SessionDeviceLogs.js +271 -0
  139. package/lib/src/services/logcat/deviceLogBook.js +163 -0
  140. package/lib/src/services/ocr/ocrData.js +118 -0
  141. package/lib/src/services/ocr/vendor/LICENSE-tessdata.txt +202 -0
  142. package/lib/src/services/ocr/vendor/eng.traineddata.gz +0 -0
  143. package/lib/src/services/omni-vision/OmniVisionService.js +83 -56
  144. package/lib/src/services/passwordResetLink.js +50 -9
  145. package/lib/src/services/passwordResetMode.js +3 -1
  146. package/lib/src/services/publicUrl.js +45 -0
  147. package/lib/src/services/session/sessionIdentity.js +5 -3
  148. package/lib/src/services/session/shutdownReason.js +26 -0
  149. package/lib/src/services/settings/aiEngineSettings.js +219 -0
  150. package/lib/src/services/token/mintedLifetime.js +51 -0
  151. package/lib/src/sessions/SessionManager.js +8 -2
  152. package/lib/src/sessions/sessionMemory.js +25 -0
  153. package/lib/test/helpers/fake-ai-provider.js +188 -0
  154. package/lib/test/helpers/loki-stores.js +33 -0
  155. package/lib/test/helpers/page-sources.js +164 -0
  156. package/lib/test/helpers/scratch-database.js +57 -13
  157. package/lib/test/integration/audit-ingest.spec.js +10 -10
  158. package/lib/test/integration/auth-flow.spec.js +9 -14
  159. package/lib/test/integration/auth-rate-limit.spec.js +6 -3
  160. package/lib/test/integration/bug-report-route.spec.js +22 -2
  161. package/lib/test/integration/forgot-password-rate-limit.spec.js +6 -3
  162. package/lib/test/integration/forgot-password.spec.js +17 -18
  163. package/lib/test/integration/legacy-deprecation-headers.spec.js +5 -2
  164. package/lib/test/integration/migration.spec.js +6 -1
  165. package/lib/test/integration/node-pair-auth-rest.spec.js +5 -9
  166. package/lib/test/integration/ports-router.spec.js +4 -4
  167. package/lib/test/integration/prisma-device-store-add-devices.spec.js +2 -3
  168. package/lib/test/integration/prisma-device-store-team-filter.spec.js +2 -5
  169. package/lib/test/integration/profile-tokens.spec.js +10 -16
  170. package/lib/test/integration/recordings-router.spec.js +16 -16
  171. package/lib/test/integration/reset-revokes-sessions.spec.js +4 -9
  172. package/lib/test/integration/role-matrix.spec.js +4 -9
  173. package/lib/test/integration/sdk-leases-router.spec.js +9 -9
  174. package/lib/test/integration/sdk-version.spec.js +2 -2
  175. package/lib/test/integration/selector-health-endpoint.spec.js +5 -5
  176. package/lib/test/integration/team-membership-migration.spec.js +73 -12
  177. package/lib/test/integration/team-visibility-apps.spec.js +15 -22
  178. package/lib/test/integration/team-visibility-control.spec.js +96 -69
  179. package/lib/test/integration/team-visibility-dashboard.spec.js +7 -23
  180. package/lib/test/integration/team-visibility-grid.spec.js +16 -15
  181. package/lib/test/integration/team-visibility-leases.spec.js +8 -11
  182. package/lib/test/integration/team-visibility-recordings.spec.js +6 -19
  183. package/lib/test/integration/team-visibility-sessions.spec.js +6 -19
  184. package/lib/test/integration/users-flow.spec.js +7 -12
  185. package/lib/test/integration/users-lockout.spec.js +5 -3
  186. package/lib/test/unit/EmailService.test.js +66 -0
  187. package/lib/test/unit/ResilioTreeHealingProvider.test.js +46 -19
  188. package/lib/test/unit/ai-call-time-limit.spec.js +130 -0
  189. package/lib/test/unit/ai-engine-settings.spec.js +338 -0
  190. package/lib/test/unit/ai-provider-switch.spec.js +130 -0
  191. package/lib/test/unit/ai-rate-limit.spec.js +126 -0
  192. package/lib/test/unit/android-h264-viewers.spec.js +272 -0
  193. package/lib/test/unit/android-preview-hold.spec.js +3 -2
  194. package/lib/test/unit/apikeys-router.spec.js +84 -0
  195. package/lib/test/unit/authMiddleware.bearer.spec.js +9 -0
  196. package/lib/test/unit/authMiddleware.credentialLifetime.spec.js +149 -0
  197. package/lib/test/unit/bug-report/video-slice.spec.js +19 -0
  198. package/lib/test/unit/dashboard-events-device-logs.spec.js +207 -0
  199. package/lib/test/unit/dashboard-plugin-link.spec.js +213 -0
  200. package/lib/test/unit/device-log-book.spec.js +180 -0
  201. package/lib/test/unit/enable-dashboard-option.spec.js +57 -0
  202. package/lib/test/unit/event-log-session-data.spec.js +244 -0
  203. package/lib/test/unit/failure-analysis.spec.js +182 -0
  204. package/lib/test/unit/failure-categories.spec.js +128 -0
  205. package/lib/test/unit/fingerprint-identity.spec.js +433 -0
  206. package/lib/test/unit/h264-multiplexer.spec.js +46 -0
  207. package/lib/test/unit/heal-report.spec.js +71 -0
  208. package/lib/test/unit/healing-instrumentation.spec.js +6 -1
  209. package/lib/test/unit/healing-tier-gate.spec.js +73 -29
  210. package/lib/test/unit/healing-tiers-every-session.spec.js +219 -0
  211. package/lib/test/unit/hub-node-gateway-appium-server.spec.js +171 -0
  212. package/lib/test/unit/interceptor-visual-elements.spec.js +192 -0
  213. package/lib/test/unit/lease/lease-override.spec.js +23 -6
  214. package/lib/test/unit/lease/session-lease-proof.spec.js +16 -4
  215. package/lib/test/unit/ocr-healing-tier-real-ocr.spec.js +113 -0
  216. package/lib/test/unit/ocr-healing-tier.spec.js +122 -0
  217. package/lib/test/unit/ocr-offline.spec.js +213 -0
  218. package/lib/test/unit/omni-virtual-element-store.spec.js +301 -0
  219. package/lib/test/unit/omni-vision-ios-points.spec.js +0 -2
  220. package/lib/test/unit/omni-vision.spec.js +5 -7
  221. package/lib/test/unit/package-engines.spec.js +27 -0
  222. package/lib/test/unit/passwordResetMode.test.js +10 -2
  223. package/lib/test/unit/profile-router.test.js +122 -1
  224. package/lib/test/unit/queue-requester.spec.js +1 -1
  225. package/lib/test/unit/reset-link-address.spec.js +266 -0
  226. package/lib/test/unit/reset-link.test.js +10 -4
  227. package/lib/test/unit/resilio-path-healing.spec.js +270 -0
  228. package/lib/test/unit/selector-learning-every-session.spec.js +179 -0
  229. package/lib/test/unit/selector-verification-clean-build.spec.js +130 -0
  230. package/lib/test/unit/selector-verification-job.spec.js +13 -13
  231. package/lib/test/unit/self-healing-boot.spec.js +10 -5
  232. package/lib/test/unit/self-healing-setting.spec.js +7 -6
  233. package/lib/test/unit/session-app-resolution.spec.js +5 -1
  234. package/lib/test/unit/session-attribution-wiring.spec.js +41 -13
  235. package/lib/test/unit/session-create-credential-owner.spec.js +242 -0
  236. package/lib/test/unit/session-credential-strip.spec.js +1 -1
  237. package/lib/test/unit/session-device-logs.spec.js +347 -0
  238. package/lib/test/unit/session-end-failure-analysis.spec.js +133 -0
  239. package/lib/test/unit/session-log-indexes.spec.js +64 -3
  240. package/lib/test/unit/socketServer.sessionCookie.spec.js +2 -1
  241. package/lib/test/unit/stream-start-pipelines.spec.js +72 -18
  242. package/lib/test/unit/token-mint-limits.spec.js +165 -0
  243. package/lib/test/unit/unexpected-shutdown-reason.spec.js +163 -0
  244. package/lib/test/unit/verify-credential.spec.js +33 -0
  245. package/lib/test/unit/vision-assertion.spec.js +3 -2
  246. package/lib/test/unit/web-config-service.spec.js +19 -0
  247. package/lib/tsconfig.tsbuildinfo +1 -1
  248. package/package.json +5 -5
  249. package/prisma/migrations/20261004174413_locator_etalon_path/migration.sql +2 -0
  250. package/prisma/schema.prisma +3 -0
  251. package/schema.json +5 -5
  252. package/lib/public/assets/BugReportButton-BAt0_pzq.js +0 -15
  253. package/lib/public/assets/DeviceMosaicView-BYaQHhTf.js +0 -2
  254. package/lib/public/assets/ai-settings-CsuJroRf.js +0 -21
  255. package/lib/public/assets/device-explorer-CdO6_nrn.js +0 -282
  256. package/lib/public/assets/forgot-password-CGnkRgE9.js +0 -1
  257. package/lib/public/assets/runbook-page-CMMeQml9.js +0 -124
  258. package/lib/public/assets/session-detail-page-COL_RZxw.js +0 -4
  259. /package/lib/public/assets/{BugReportButton-CPBjfiv4.css → index-CPBjfiv4.css} +0 -0
@@ -14,13 +14,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  require("reflect-metadata");
16
16
  const chai_1 = require("chai");
17
- const supertest_1 = __importDefault(require("supertest"));
17
+ const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
18
18
  const express_1 = __importDefault(require("express"));
19
19
  const auth_1 = require("../../src/app/routers/auth");
20
20
  const authMiddleware_1 = require("../../src/middleware/authMiddleware");
21
- const prisma_1 = require("../../src/prisma");
22
21
  const typedi_1 = require("typedi");
23
22
  const UserService_1 = require("../../src/services/UserService");
23
+ const scratch_database_1 = require("../helpers/scratch-database");
24
24
  function buildApp() {
25
25
  const app = (0, express_1.default)();
26
26
  app.use(express_1.default.json());
@@ -32,10 +32,9 @@ function buildApp() {
32
32
  }
33
33
  describe('auth flow (integration)', function () {
34
34
  this.timeout(30000);
35
+ (0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
35
36
  let user;
36
37
  before(() => __awaiter(this, void 0, void 0, function* () {
37
- yield prisma_1.prisma.userSession.deleteMany({ where: { user: { email: 'loginflow@xenon.local' } } });
38
- yield prisma_1.prisma.user.deleteMany({ where: { email: 'loginflow@xenon.local' } });
39
38
  user = yield typedi_1.Container.get(UserService_1.UserService).createUser({
40
39
  email: 'loginflow@xenon.local',
41
40
  name: 'Login Flow',
@@ -43,31 +42,27 @@ describe('auth flow (integration)', function () {
43
42
  role: 'ADMIN',
44
43
  });
45
44
  }));
46
- after(() => __awaiter(this, void 0, void 0, function* () {
47
- yield prisma_1.prisma.userSession.deleteMany({ where: { userId: user.id } });
48
- yield prisma_1.prisma.user.delete({ where: { id: user.id } });
49
- }));
50
45
  it('login → cookie → /whoami → logout → 401', () => __awaiter(this, void 0, void 0, function* () {
51
46
  var _a;
52
47
  const app = buildApp();
53
- const login = yield (0, supertest_1.default)(app)
48
+ const login = yield (0, loopbackRequest_1.default)(app)
54
49
  .post('/api/auth/login')
55
50
  .send({ email: 'loginflow@xenon.local', password: 'flow-test-12' });
56
51
  (0, chai_1.expect)(login.status).to.equal(204);
57
52
  const cookie = (_a = login.headers['set-cookie']) === null || _a === void 0 ? void 0 : _a[0];
58
53
  (0, chai_1.expect)(cookie).to.match(/^xenon_dashboard_session=/);
59
- const me = yield (0, supertest_1.default)(app).get('/api/whoami').set('Cookie', cookie);
54
+ const me = yield (0, loopbackRequest_1.default)(app).get('/api/whoami').set('Cookie', cookie);
60
55
  (0, chai_1.expect)(me.status).to.equal(200);
61
56
  (0, chai_1.expect)(me.body.userId).to.equal(user.id);
62
57
  (0, chai_1.expect)(me.body.kind).to.equal('user-session');
63
- const out = yield (0, supertest_1.default)(app).post('/api/auth/logout').set('Cookie', cookie);
58
+ const out = yield (0, loopbackRequest_1.default)(app).post('/api/auth/logout').set('Cookie', cookie);
64
59
  (0, chai_1.expect)(out.status).to.equal(204);
65
- const me2 = yield (0, supertest_1.default)(app).get('/api/whoami').set('Cookie', cookie);
60
+ const me2 = yield (0, loopbackRequest_1.default)(app).get('/api/whoami').set('Cookie', cookie);
66
61
  (0, chai_1.expect)(me2.status).to.equal(401);
67
62
  }));
68
63
  it('login with wrong password returns generic 401 (no enumeration)', () => __awaiter(this, void 0, void 0, function* () {
69
64
  const app = buildApp();
70
- const login = yield (0, supertest_1.default)(app)
65
+ const login = yield (0, loopbackRequest_1.default)(app)
71
66
  .post('/api/auth/login')
72
67
  .send({ email: 'loginflow@xenon.local', password: 'WRONG' });
73
68
  (0, chai_1.expect)(login.status).to.equal(401);
@@ -75,7 +70,7 @@ describe('auth flow (integration)', function () {
75
70
  }));
76
71
  it('login with unknown email returns the same generic 401', () => __awaiter(this, void 0, void 0, function* () {
77
72
  const app = buildApp();
78
- const login = yield (0, supertest_1.default)(app)
73
+ const login = yield (0, loopbackRequest_1.default)(app)
79
74
  .post('/api/auth/login')
80
75
  .send({ email: 'no-such@xenon.local', password: 'whatever' });
81
76
  (0, chai_1.expect)(login.status).to.equal(401);
@@ -15,22 +15,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  require("reflect-metadata");
16
16
  const chai_1 = require("chai");
17
17
  const express_1 = __importDefault(require("express"));
18
- const supertest_1 = __importDefault(require("supertest"));
18
+ const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
19
19
  const auth_1 = require("../../src/app/routers/auth");
20
+ const scratch_database_1 = require("../helpers/scratch-database");
20
21
  describe('login rate limit', function () {
21
22
  this.timeout(15000);
23
+ // Each attempt looks the email address up.
24
+ (0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
22
25
  it('5 bad logins from one IP → 6th returns 429 with Retry-After', () => __awaiter(this, void 0, void 0, function* () {
23
26
  const app = (0, express_1.default)();
24
27
  app.use(express_1.default.json());
25
28
  app.use('/auth', (0, auth_1.authPublicRouter)());
26
29
  for (let i = 0; i < 5; i++) {
27
- const r = yield (0, supertest_1.default)(app)
30
+ const r = yield (0, loopbackRequest_1.default)(app)
28
31
  .post('/auth/login')
29
32
  .set('X-Forwarded-For', '9.9.9.9')
30
33
  .send({ email: 'no@no.com', password: 'no' });
31
34
  (0, chai_1.expect)(r.status).to.equal(401);
32
35
  }
33
- const blocked = yield (0, supertest_1.default)(app)
36
+ const blocked = yield (0, loopbackRequest_1.default)(app)
34
37
  .post('/auth/login')
35
38
  .set('X-Forwarded-For', '9.9.9.9')
36
39
  .send({ email: 'no@no.com', password: 'no' });
@@ -48,7 +48,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
48
48
  require("reflect-metadata");
49
49
  const chai_1 = require("chai");
50
50
  const express_1 = __importDefault(require("express"));
51
- const supertest_1 = __importDefault(require("supertest"));
51
+ const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
52
52
  const sinon_1 = __importDefault(require("sinon"));
53
53
  const fs = __importStar(require("fs"));
54
54
  const path = __importStar(require("path"));
@@ -57,11 +57,14 @@ const unzipper = __importStar(require("unzipper"));
57
57
  const prisma_1 = require("../../src/prisma");
58
58
  const config_1 = require("../../src/config");
59
59
  const bug_report_1 = __importDefault(require("../../src/app/routers/bug-report"));
60
+ const authMiddleware_1 = require("../../src/middleware/authMiddleware");
60
61
  describe('POST /sessions/:id/bug-report (integration)', () => {
61
62
  let tmpAssets;
63
+ let savedAssetsPath;
62
64
  const fixtureMp4 = path.join(__dirname, 'fixtures/bug-report/recording.mp4');
63
65
  beforeEach(() => {
64
66
  tmpAssets = fs.mkdtempSync(path.join(os.tmpdir(), 'xenon-it-'));
67
+ savedAssetsPath = config_1.config.sessionAssetsPath;
65
68
  config_1.config.sessionAssetsPath = tmpAssets;
66
69
  const sessionDir = path.join(tmpAssets, 'sess-it', 'video');
67
70
  fs.mkdirSync(sessionDir, { recursive: true });
@@ -69,10 +72,27 @@ describe('POST /sessions/:id/bug-report (integration)', () => {
69
72
  });
70
73
  afterEach(() => {
71
74
  sinon_1.default.restore();
75
+ config_1.config.sessionAssetsPath = savedAssetsPath;
72
76
  fs.rmSync(tmpAssets, { recursive: true, force: true });
73
77
  });
78
+ /**
79
+ * The router sits behind authMiddleware in the API, and its roleGuard
80
+ * answers 401 to a request with no `req.auth` (27fd825, three days after
81
+ * this spec). Stand in for the middleware with an admin, as it sets one:
82
+ * no `teamIds`, so the session needs no Device row to be visible.
83
+ */
74
84
  function makeApp() {
75
85
  const app = (0, express_1.default)();
86
+ app.use((req, _res, next) => {
87
+ req.auth = {
88
+ kind: 'user-session',
89
+ userId: 'usr_admin',
90
+ role: 'ADMIN',
91
+ scopes: (0, authMiddleware_1.scopesForRole)('ADMIN'),
92
+ rateLimit: 100,
93
+ };
94
+ next();
95
+ });
76
96
  bug_report_1.default.register(app);
77
97
  return app;
78
98
  }
@@ -94,7 +114,7 @@ describe('POST /sessions/:id/bug-report (integration)', () => {
94
114
  sinon_1.default.stub(prisma_1.prisma.sessionLog, 'findMany').resolves([
95
115
  { createdAt: new Date(), title: 'click', response: 'fail' },
96
116
  ]);
97
- const res = yield (0, supertest_1.default)(makeApp())
117
+ const res = yield (0, loopbackRequest_1.default)(makeApp())
98
118
  .post('/sessions/sess-it/bug-report?mode=full')
99
119
  .buffer(true)
100
120
  .parse((r, cb) => {
@@ -15,22 +15,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  require("reflect-metadata");
16
16
  const chai_1 = require("chai");
17
17
  const express_1 = __importDefault(require("express"));
18
- const supertest_1 = __importDefault(require("supertest"));
18
+ const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
19
19
  const auth_1 = require("../../src/app/routers/auth");
20
+ const scratch_database_1 = require("../helpers/scratch-database");
20
21
  describe('forgot-password rate limit', function () {
21
22
  this.timeout(15000);
23
+ // Each attempt looks the email address up.
24
+ (0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
22
25
  it('3 attempts from one IP -> 4th returns 429 with Retry-After', () => __awaiter(this, void 0, void 0, function* () {
23
26
  const app = (0, express_1.default)();
24
27
  app.use(express_1.default.json());
25
28
  app.use('/auth', (0, auth_1.authPublicRouter)());
26
29
  for (let i = 0; i < 3; i++) {
27
- const r = yield (0, supertest_1.default)(app)
30
+ const r = yield (0, loopbackRequest_1.default)(app)
28
31
  .post('/auth/forgot-password')
29
32
  .set('X-Forwarded-For', '7.7.7.7')
30
33
  .send({ email: 'whatever@xenon.local' });
31
34
  (0, chai_1.expect)(r.status).to.equal(204);
32
35
  }
33
- const blocked = yield (0, supertest_1.default)(app)
36
+ const blocked = yield (0, loopbackRequest_1.default)(app)
34
37
  .post('/auth/forgot-password')
35
38
  .set('X-Forwarded-For', '7.7.7.7')
36
39
  .send({ email: 'whatever@xenon.local' });
@@ -15,20 +15,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  require("reflect-metadata");
16
16
  const chai_1 = require("chai");
17
17
  const express_1 = __importDefault(require("express"));
18
- const supertest_1 = __importDefault(require("supertest"));
18
+ const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
19
19
  const auth_1 = require("../../src/app/routers/auth");
20
20
  const typedi_1 = require("typedi");
21
21
  const UserService_1 = require("../../src/services/UserService");
22
22
  const PasswordResetService_1 = require("../../src/services/PasswordResetService");
23
23
  const prisma_1 = require("../../src/prisma");
24
+ const scratch_database_1 = require("../helpers/scratch-database");
24
25
  describe('forgot-password flow (integration)', function () {
25
26
  this.timeout(30000);
27
+ (0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
26
28
  let user;
27
29
  const email = 'forgot-it@xenon.local';
28
30
  before(() => __awaiter(this, void 0, void 0, function* () {
29
- yield prisma_1.prisma.passwordResetToken.deleteMany({ where: { user: { email } } });
30
- yield prisma_1.prisma.userSession.deleteMany({ where: { user: { email } } });
31
- yield prisma_1.prisma.user.deleteMany({ where: { email } });
32
31
  user = yield typedi_1.Container.get(UserService_1.UserService).createUser({
33
32
  email,
34
33
  name: 'Forgot IT',
@@ -36,42 +35,41 @@ describe('forgot-password flow (integration)', function () {
36
35
  role: 'ADMIN',
37
36
  });
38
37
  }));
39
- after(() => __awaiter(this, void 0, void 0, function* () {
40
- yield prisma_1.prisma.passwordResetToken.deleteMany({ where: { userId: user.id } });
41
- yield prisma_1.prisma.userSession.deleteMany({ where: { userId: user.id } });
42
- yield prisma_1.prisma.user.delete({ where: { id: user.id } });
43
- }));
44
38
  function buildApp() {
45
39
  const app = (0, express_1.default)();
46
40
  app.use(express_1.default.json());
47
41
  app.use('/auth', (0, auth_1.authPublicRouter)());
48
42
  return app;
49
43
  }
44
+ // A POST with the token in the body: since #265 the token stays out of
45
+ // request URLs, which the server log records. The old GET /check/:token is
46
+ // gone, so it answered 404 to every token, valid or not.
47
+ const check = (app, token) => (0, loopbackRequest_1.default)(app).post('/auth/reset-password/check').send({ token });
50
48
  it('full flow: forgot -> DB token -> reset -> login with new password', () => __awaiter(this, void 0, void 0, function* () {
51
49
  const app = buildApp();
52
50
  // Generic 204 even with wrong email
53
- const r1 = yield (0, supertest_1.default)(app).post('/auth/forgot-password').send({ email: 'no@no.com' });
51
+ const r1 = yield (0, loopbackRequest_1.default)(app).post('/auth/forgot-password').send({ email: 'no@no.com' });
54
52
  (0, chai_1.expect)(r1.status).to.equal(204);
55
- const r2 = yield (0, supertest_1.default)(app).post('/auth/forgot-password').send({ email });
53
+ const r2 = yield (0, loopbackRequest_1.default)(app).post('/auth/forgot-password').send({ email });
56
54
  (0, chai_1.expect)(r2.status).to.equal(204);
57
55
  // Generate a token via the service directly so we have the raw value to reset with
58
56
  const { raw } = yield typedi_1.Container.get(PasswordResetService_1.PasswordResetService).createToken(user.id);
59
- const check = yield (0, supertest_1.default)(app).get(`/auth/reset-password/check/${raw}`);
60
- (0, chai_1.expect)(check.status).to.equal(200);
61
- const reset = yield (0, supertest_1.default)(app)
57
+ const valid = yield check(app, raw);
58
+ (0, chai_1.expect)(valid.status).to.equal(200);
59
+ const reset = yield (0, loopbackRequest_1.default)(app)
62
60
  .post('/auth/reset-password')
63
61
  .send({ token: raw, newPassword: 'NewPassw0rd1' });
64
62
  (0, chai_1.expect)(reset.status).to.equal(204);
65
63
  // Token now consumed
66
- const recheck = yield (0, supertest_1.default)(app).get(`/auth/reset-password/check/${raw}`);
64
+ const recheck = yield check(app, raw);
67
65
  (0, chai_1.expect)(recheck.status).to.equal(404);
68
66
  // Login with new password works
69
- const login = yield (0, supertest_1.default)(app)
67
+ const login = yield (0, loopbackRequest_1.default)(app)
70
68
  .post('/auth/login')
71
69
  .send({ email, password: 'NewPassw0rd1' });
72
70
  (0, chai_1.expect)(login.status).to.equal(204);
73
71
  // Login with old password fails
74
- const oldLogin = yield (0, supertest_1.default)(app)
72
+ const oldLogin = yield (0, loopbackRequest_1.default)(app)
75
73
  .post('/auth/login')
76
74
  .send({ email, password: 'old-password-1' });
77
75
  (0, chai_1.expect)(oldLogin.status).to.equal(401);
@@ -83,7 +81,8 @@ describe('forgot-password flow (integration)', function () {
83
81
  data: { expiresAt: new Date(Date.now() - 1000) },
84
82
  });
85
83
  const app = buildApp();
86
- const r = yield (0, supertest_1.default)(app).get(`/auth/reset-password/check/${raw}`);
84
+ const r = yield check(app, raw);
87
85
  (0, chai_1.expect)(r.status).to.equal(404);
86
+ (0, chai_1.expect)(r.body).to.deep.equal({ error: 'invalid or expired token' });
88
87
  }));
89
88
  });
@@ -48,8 +48,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
48
48
  require("reflect-metadata");
49
49
  const chai_1 = require("chai");
50
50
  const express_1 = __importDefault(require("express"));
51
- const supertest_1 = __importDefault(require("supertest"));
51
+ const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
52
+ const scratch_database_1 = require("../helpers/scratch-database");
52
53
  describe('legacy /reservation headers', () => {
54
+ // The route reads the phones' reservations from the database.
55
+ (0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
53
56
  it('GET /reservation returns Deprecation + Sunset + Link headers', () => __awaiter(void 0, void 0, void 0, function* () {
54
57
  const router = (yield Promise.resolve().then(() => __importStar(require('../../src/app/routers/reservation')))).default;
55
58
  const app = (0, express_1.default)();
@@ -60,7 +63,7 @@ describe('legacy /reservation headers', () => {
60
63
  next();
61
64
  });
62
65
  app.use('/reservation', router);
63
- const res = yield (0, supertest_1.default)(app).get('/reservation');
66
+ const res = yield (0, loopbackRequest_1.default)(app).get('/reservation');
64
67
  (0, chai_1.expect)(res.headers['deprecation']).to.equal('true');
65
68
  (0, chai_1.expect)(res.headers['sunset']).to.match(/^\d{4}-\d{2}-\d{2}T/);
66
69
  (0, chai_1.expect)(res.headers['link']).to.include('rel="alternate"');
@@ -13,15 +13,20 @@ require("reflect-metadata");
13
13
  const chai_1 = require("chai");
14
14
  const bootstrap_1 = require("../../src/services/identity/bootstrap");
15
15
  const prisma_1 = require("../../src/prisma");
16
+ const scratch_database_1 = require("../helpers/scratch-database");
16
17
  describe('bootstrapIdentity idempotency (integration)', function () {
17
18
  this.timeout(30000);
19
+ (0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
20
+ // On a fresh database, so the first run has a super-admin to create. On a
21
+ // developer's populated one both runs returned at once and proved nothing.
18
22
  it('running twice does not create duplicate users', () => __awaiter(this, void 0, void 0, function* () {
19
23
  const before = yield prisma_1.prisma.user.count();
24
+ (0, chai_1.expect)(before, 'a fresh database').to.equal(0);
20
25
  yield (0, bootstrap_1.bootstrapIdentity)();
21
26
  const after1 = yield prisma_1.prisma.user.count();
27
+ (0, chai_1.expect)(after1, 'the bootstrap super-admin').to.equal(1);
22
28
  yield (0, bootstrap_1.bootstrapIdentity)();
23
29
  const after2 = yield prisma_1.prisma.user.count();
24
30
  (0, chai_1.expect)(after2).to.equal(after1);
25
- (0, chai_1.expect)(after1).to.be.greaterThanOrEqual(before);
26
31
  }));
27
32
  });
@@ -15,15 +15,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  require("reflect-metadata");
16
16
  const chai_1 = require("chai");
17
17
  const express_1 = __importDefault(require("express"));
18
- const supertest_1 = __importDefault(require("supertest"));
18
+ const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
19
19
  const authMiddleware_1 = require("../../src/middleware/authMiddleware");
20
20
  const grid_1 = __importDefault(require("../../src/app/routers/grid"));
21
21
  const typedi_1 = require("typedi");
22
22
  const UserService_1 = require("../../src/services/UserService");
23
23
  const ApiKeyService_1 = require("../../src/services/ApiKeyService");
24
- const prisma_1 = require("../../src/prisma");
24
+ const scratch_database_1 = require("../helpers/scratch-database");
25
25
  describe('node pair auth — REST /register (integration)', function () {
26
26
  this.timeout(60000);
27
+ (0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
27
28
  let nodeUser;
28
29
  let rawToken;
29
30
  before(() => __awaiter(this, void 0, void 0, function* () {
@@ -41,11 +42,6 @@ describe('node pair auth — REST /register (integration)', function () {
41
42
  });
42
43
  rawToken = tok.raw;
43
44
  }));
44
- after(() => __awaiter(this, void 0, void 0, function* () {
45
- yield prisma_1.prisma.apiKey.deleteMany({ where: { userId: nodeUser.id } });
46
- yield prisma_1.prisma.userSession.deleteMany({ where: { userId: nodeUser.id } });
47
- yield prisma_1.prisma.user.delete({ where: { id: nodeUser.id } });
48
- }));
49
45
  function buildApp() {
50
46
  const app = (0, express_1.default)();
51
47
  app.use(express_1.default.json());
@@ -54,7 +50,7 @@ describe('node pair auth — REST /register (integration)', function () {
54
50
  return app;
55
51
  }
56
52
  it('pair (accessKey, token) → not 401/403', () => __awaiter(this, void 0, void 0, function* () {
57
- const r = yield (0, supertest_1.default)(buildApp())
53
+ const r = yield (0, loopbackRequest_1.default)(buildApp())
58
54
  .post('/register')
59
55
  .query({ type: 'add' })
60
56
  .set('x-xenon-access-key', nodeUser.accessKey)
@@ -64,7 +60,7 @@ describe('node pair auth — REST /register (integration)', function () {
64
60
  (0, chai_1.expect)(r.status).to.not.equal(403);
65
61
  }));
66
62
  it('no auth headers → 401', () => __awaiter(this, void 0, void 0, function* () {
67
- const r = yield (0, supertest_1.default)(buildApp())
63
+ const r = yield (0, loopbackRequest_1.default)(buildApp())
68
64
  .post('/register')
69
65
  .query({ type: 'add' })
70
66
  .send([]);
@@ -48,7 +48,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
48
48
  require("reflect-metadata");
49
49
  const chai_1 = require("chai");
50
50
  const express_1 = __importDefault(require("express"));
51
- const supertest_1 = __importDefault(require("supertest"));
51
+ const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
52
52
  const sinon_1 = __importDefault(require("sinon"));
53
53
  describe('POST /xenon/api/ports/allocate', () => {
54
54
  let app;
@@ -62,7 +62,7 @@ describe('POST /xenon/api/ports/allocate', () => {
62
62
  app.use('/xenon/api/ports', router.makeRouter({ allocator: { allocate: allocateStub } }));
63
63
  }));
64
64
  it('returns 200 with the allocated ports', () => __awaiter(void 0, void 0, void 0, function* () {
65
- const res = yield (0, supertest_1.default)(app)
65
+ const res = yield (0, loopbackRequest_1.default)(app)
66
66
  .post('/xenon/api/ports/allocate')
67
67
  .send({ udid: 'u1', host: 'h1', purposes: ['systemPort', 'chromedriverPort'], durationMs: 60000 });
68
68
  (0, chai_1.expect)(res.status).to.equal(200);
@@ -70,14 +70,14 @@ describe('POST /xenon/api/ports/allocate', () => {
70
70
  (0, chai_1.expect)(allocateStub.calledOnce).to.equal(true);
71
71
  }));
72
72
  it('returns 400 when purposes is missing or empty', () => __awaiter(void 0, void 0, void 0, function* () {
73
- const res = yield (0, supertest_1.default)(app)
73
+ const res = yield (0, loopbackRequest_1.default)(app)
74
74
  .post('/xenon/api/ports/allocate')
75
75
  .send({ udid: 'u1', host: 'h1', durationMs: 60000 });
76
76
  (0, chai_1.expect)(res.status).to.equal(400);
77
77
  }));
78
78
  it('returns 500 on allocator failure', () => __awaiter(void 0, void 0, void 0, function* () {
79
79
  allocateStub.rejects(new Error('boom'));
80
- const res = yield (0, supertest_1.default)(app)
80
+ const res = yield (0, loopbackRequest_1.default)(app)
81
81
  .post('/xenon/api/ports/allocate')
82
82
  .send({ udid: 'u1', host: 'h1', purposes: ['systemPort'], durationMs: 60000 });
83
83
  (0, chai_1.expect)(res.status).to.equal(500);
@@ -13,6 +13,7 @@ require("reflect-metadata");
13
13
  const chai_1 = require("chai");
14
14
  const prisma_store_1 = require("../../src/data-service/prisma-store");
15
15
  const prisma_1 = require("../../src/prisma");
16
+ const scratch_database_1 = require("../helpers/scratch-database");
16
17
  /**
17
18
  * PrismaDeviceStore.addDevices, run as real queries.
18
19
  *
@@ -23,6 +24,7 @@ const prisma_1 = require("../../src/prisma");
23
24
  */
24
25
  describe('PrismaDeviceStore.addDevices (integration)', function () {
25
26
  this.timeout(60000);
27
+ (0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
26
28
  const store = new prisma_store_1.PrismaDeviceStore();
27
29
  const stamp = Date.now();
28
30
  const HOST = `http://add-devices-${stamp}:4723`;
@@ -46,9 +48,6 @@ describe('PrismaDeviceStore.addDevices (integration)', function () {
46
48
  },
47
49
  });
48
50
  }));
49
- after(() => __awaiter(this, void 0, void 0, function* () {
50
- yield prisma_1.prisma.device.deleteMany({ where: { udid: { in: UDIDS } } });
51
- }));
52
51
  it('refreshes a known phone’s discovery columns but leaves its session alone', () => __awaiter(this, void 0, void 0, function* () {
53
52
  const added = yield store.addDevices([phone(KNOWN, { sdk: '11', sessionStartTime: 0 })]);
54
53
  (0, chai_1.expect)(added).to.deep.equal([]);
@@ -15,6 +15,7 @@ const typedi_1 = require("typedi");
15
15
  const prisma_store_1 = require("../../src/data-service/prisma-store");
16
16
  const TeamService_1 = require("../../src/services/TeamService");
17
17
  const prisma_1 = require("../../src/prisma");
18
+ const scratch_database_1 = require("../helpers/scratch-database");
18
19
  /**
19
20
  * The team filter on the Prisma device store, run as a real query.
20
21
  *
@@ -25,6 +26,7 @@ const prisma_1 = require("../../src/prisma");
25
26
  */
26
27
  describe('PrismaDeviceStore team filter (integration)', function () {
27
28
  this.timeout(60000);
29
+ (0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
28
30
  const store = new prisma_store_1.PrismaDeviceStore();
29
31
  let teamA;
30
32
  let teamB;
@@ -51,11 +53,6 @@ describe('PrismaDeviceStore team filter (integration)', function () {
51
53
  beforeEach(() => __awaiter(this, void 0, void 0, function* () {
52
54
  yield prisma_1.prisma.device.updateMany({ where: { udid: { in: UDIDS } }, data: { busy: false } });
53
55
  }));
54
- after(() => __awaiter(this, void 0, void 0, function* () {
55
- yield prisma_1.prisma.device.deleteMany({ where: { udid: { in: UDIDS } } });
56
- yield prisma_1.prisma.team.delete({ where: { id: teamA.id } }).catch(() => undefined);
57
- yield prisma_1.prisma.team.delete({ where: { id: teamB.id } }).catch(() => undefined);
58
- }));
59
56
  const udidsOf = (rows) => rows.map((r) => r.udid).sort();
60
57
  const busy = (udid) => __awaiter(this, void 0, void 0, function* () { var _a; return !!((_a = (yield prisma_1.prisma.device.findFirst({ where: { udid, host: HOST } }))) === null || _a === void 0 ? void 0 : _a.busy); });
61
58
  it('getDevices with one team returns the shared phone and that team’s', () => __awaiter(this, void 0, void 0, function* () {
@@ -15,20 +15,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  require("reflect-metadata");
16
16
  const chai_1 = require("chai");
17
17
  const express_1 = __importDefault(require("express"));
18
- const supertest_1 = __importDefault(require("supertest"));
18
+ const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
19
19
  const profile_1 = require("../../src/app/routers/profile");
20
20
  const authMiddleware_1 = require("../../src/middleware/authMiddleware");
21
21
  const typedi_1 = require("typedi");
22
22
  const UserService_1 = require("../../src/services/UserService");
23
23
  const UserSessionService_1 = require("../../src/services/UserSessionService");
24
- const prisma_1 = require("../../src/prisma");
24
+ const scratch_database_1 = require("../helpers/scratch-database");
25
25
  describe('profile/tokens (integration)', function () {
26
26
  this.timeout(30000);
27
+ (0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
27
28
  let user;
28
29
  let cookie;
29
30
  before(() => __awaiter(this, void 0, void 0, function* () {
30
- yield prisma_1.prisma.userSession.deleteMany({ where: { user: { email: 'tokens-it@xenon.local' } } });
31
- yield prisma_1.prisma.user.deleteMany({ where: { email: 'tokens-it@xenon.local' } });
32
31
  user = yield typedi_1.Container.get(UserService_1.UserService).createUser({
33
32
  email: 'tokens-it@xenon.local',
34
33
  name: 'Tokens IT',
@@ -38,40 +37,35 @@ describe('profile/tokens (integration)', function () {
38
37
  const session = yield typedi_1.Container.get(UserSessionService_1.UserSessionService).create(user.id);
39
38
  cookie = `xenon_dashboard_session=${session.id}`;
40
39
  }));
41
- after(() => __awaiter(this, void 0, void 0, function* () {
42
- yield prisma_1.prisma.apiKey.deleteMany({ where: { userId: user.id } });
43
- yield prisma_1.prisma.userSession.deleteMany({ where: { userId: user.id } });
44
- yield prisma_1.prisma.user.delete({ where: { id: user.id } });
45
- }));
46
40
  it('creates and lists a token; rotating accessKey keeps the token valid', () => __awaiter(this, void 0, void 0, function* () {
47
41
  const app = (0, express_1.default)();
48
42
  app.use(express_1.default.json());
49
43
  app.use(authMiddleware_1.authMiddleware);
50
44
  app.use('/profile', (0, profile_1.profileRouter)());
51
- const created = yield (0, supertest_1.default)(app)
45
+ const created = yield (0, loopbackRequest_1.default)(app)
52
46
  .post('/profile/tokens')
53
47
  .set('Cookie', cookie)
54
48
  .send({ name: 'CI' });
55
49
  (0, chai_1.expect)(created.status).to.equal(201);
56
50
  const token = created.body.token;
57
- const list = yield (0, supertest_1.default)(app).get('/profile/tokens').set('Cookie', cookie);
51
+ const list = yield (0, loopbackRequest_1.default)(app).get('/profile/tokens').set('Cookie', cookie);
58
52
  (0, chai_1.expect)(list.body.length).to.equal(1);
59
- const me = yield (0, supertest_1.default)(app).get('/profile/access-key').set('Cookie', cookie);
53
+ const me = yield (0, loopbackRequest_1.default)(app).get('/profile/access-key').set('Cookie', cookie);
60
54
  const ak = me.body.accessKey;
61
- const headerCheck = yield (0, supertest_1.default)(app)
55
+ const headerCheck = yield (0, loopbackRequest_1.default)(app)
62
56
  .get('/profile/tokens')
63
57
  .set('x-xenon-access-key', ak)
64
58
  .set('x-xenon-token', token);
65
59
  (0, chai_1.expect)(headerCheck.status).to.equal(200);
66
- const rotated = yield (0, supertest_1.default)(app).post('/profile/access-key/rotate').set('Cookie', cookie);
60
+ const rotated = yield (0, loopbackRequest_1.default)(app).post('/profile/access-key/rotate').set('Cookie', cookie);
67
61
  const newAk = rotated.body.accessKey;
68
62
  (0, chai_1.expect)(newAk).to.not.equal(ak);
69
- const afterRotate = yield (0, supertest_1.default)(app)
63
+ const afterRotate = yield (0, loopbackRequest_1.default)(app)
70
64
  .get('/profile/tokens')
71
65
  .set('x-xenon-access-key', newAk)
72
66
  .set('x-xenon-token', token);
73
67
  (0, chai_1.expect)(afterRotate.status).to.equal(200);
74
- const oldFails = yield (0, supertest_1.default)(app)
68
+ const oldFails = yield (0, loopbackRequest_1.default)(app)
75
69
  .get('/profile/tokens')
76
70
  .set('x-xenon-access-key', ak)
77
71
  .set('x-xenon-token', token);