@xenon-device-management/xenon 2.13.2 → 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.
- package/README.md +17 -8
- package/lib/package.json +5 -5
- package/lib/public/assets/{AnnotationOverlay-BXruClDk.js → AnnotationOverlay-Btq3dZRI.js} +1 -1
- package/lib/public/assets/{ApiKeyGate-qTS4LPLC.js → ApiKeyGate-C9OoAgg_.js} +1 -1
- package/lib/public/assets/DeviceMosaicView-DBC_xczB.js +2 -0
- package/lib/public/assets/{EmptyState-Cr17PdDv.js → EmptyState-DqWU2-vM.js} +1 -1
- package/lib/public/assets/{FieldGroup-Bvn08svv.js → FieldGroup-CveQ3xrA.js} +1 -1
- package/lib/public/assets/{FilterMenu-DDSO8aDf.js → FilterMenu-BfKDSfHz.js} +1 -1
- package/lib/public/assets/{Menu-B-Qn2X3T.js → Menu-CtdCybzA.js} +1 -1
- package/lib/public/assets/{Modal-Cg9V5JYU.js → Modal-Bsvj1tm2.js} +1 -1
- package/lib/public/assets/{RecordingPage-BTUs9VTW.js → RecordingPage-CRofOiyx.js} +1 -1
- package/lib/public/assets/{RecordingsPage-DYcfxITK.js → RecordingsPage-jNQHb2IR.js} +2 -2
- package/lib/public/assets/{SegmentedControl-Zy7suhT5.js → SegmentedControl-C8HtTha-.js} +1 -1
- package/lib/public/assets/{SettingCard-CWYmycoe.js → SettingCard-D8K1LZNo.js} +1 -1
- package/lib/public/assets/{Table-io9fwa98.js → Table-zNTX92Pn.js} +1 -1
- package/lib/public/assets/{activity-Bdf_uIWl.js → activity-CJ8LwZq9.js} +1 -1
- package/lib/public/assets/ai-settings-CgxQZqrc.js +16 -0
- package/lib/public/assets/{api-keys-CPqtVpm3.js → api-keys-ECpo-zTo.js} +1 -1
- package/lib/public/assets/{apps-BgZan0H9.js → apps-BjGymyf3.js} +2 -2
- package/lib/public/assets/{arrow-left-B27ckB31.js → arrow-left-BWfCbeHP.js} +1 -1
- package/lib/public/assets/{arrow-right-DOF8ITCz.js → arrow-right-DC7UGf_n.js} +1 -1
- package/lib/public/assets/{arrow-up-right-eFG5KTFS.js → arrow-up-right-BOjwybDk.js} +1 -1
- package/lib/public/assets/{auth-shell-DlC3_27j.js → auth-shell-CxMTo9aH.js} +2 -2
- package/lib/public/assets/{builds-page-BuXpPfKo.js → builds-page-DOCm4HkA.js} +1 -1
- package/lib/public/assets/{button-fIW8owMI.js → button-Cg08-EMT.js} +1 -1
- package/lib/public/assets/{calendar-WNjmrF-a.js → calendar-CA1ikLJs.js} +1 -1
- package/lib/public/assets/{check-BdTh1Sq7.js → check-BMTaH72W.js} +1 -1
- package/lib/public/assets/{chevron-right-B4BKlsqk.js → chevron-right-B2QOv9Nx.js} +1 -1
- package/lib/public/assets/{circle-check-zJU80_EF.js → circle-check-CYXBoUqT.js} +1 -1
- package/lib/public/assets/{circle-x-5Uwquo0h.js → circle-x-DTwnSAnl.js} +1 -1
- package/lib/public/assets/{clock-BtUprDsZ.js → clock-C8_HViQP.js} +1 -1
- package/lib/public/assets/{copy-DGSbZI3u.js → copy-Be7LNMXV.js} +1 -1
- package/lib/public/assets/derive-UnLRp4r3.js +1 -0
- package/lib/public/assets/device-explorer-BOqtfGXz.js +282 -0
- package/lib/public/assets/{download-WG6l7BgD.js → download-B56lwxWP.js} +1 -1
- package/lib/public/assets/forgot-password-CCU6bzLn.js +1 -0
- package/lib/public/assets/h264Stream-C-OtmIuk.js +26 -0
- package/lib/public/assets/index-B9KQ6LsY.js +15 -0
- package/lib/public/assets/{index-DI1fGIyj.js → index-BOxe43p1.js} +5 -5
- package/lib/public/assets/{index-HDQVe1gi.js → index-CfxsUslp.js} +1 -1
- package/lib/public/assets/{input-BjDRKCea.js → input-CZHFjbSg.js} +1 -1
- package/lib/public/assets/{line-chart-C0zdgd0v.js → line-chart-Gl_Dz3X_.js} +1 -1
- package/lib/public/assets/{list-checks-BdW5CjM8.js → list-checks-CCgjeyGY.js} +1 -1
- package/lib/public/assets/{lock-Dy3L4I8E.js → lock-CkOwgDcx.js} +1 -1
- package/lib/public/assets/{login-BHbY9CLG.js → login-D5cc4w7M.js} +1 -1
- package/lib/public/assets/maintenance-settings-t7qr3fvX.js +6 -0
- package/lib/public/assets/{monitor-8xjkeHHi.js → monitor-DEJixKQO.js} +1 -1
- package/lib/public/assets/{mouse-pointer-2-CXdKMXQ8.js → mouse-pointer-2-CtOrk4M8.js} +1 -1
- package/lib/public/assets/{network-Cj8JOKON.js → network-Dii9qdvk.js} +1 -1
- package/lib/public/assets/{overview-CTg7F0im.js → overview-rolAACrO.js} +1 -1
- package/lib/public/assets/{page-header--aTyJXq6.js → page-header-COQZxJfR.js} +1 -1
- package/lib/public/assets/{play-B-FodgHV.js → play-DrN1Se_R.js} +1 -1
- package/lib/public/assets/{plus-CsIk10Cq.js → plus-5aq-9uRx.js} +1 -1
- package/lib/public/assets/{profile-page-DkFKkMfl.js → profile-page-6i5kY6kF.js} +1 -1
- package/lib/public/assets/{reset-password-I2-zqLlI.js → reset-password-sp2IBrc7.js} +1 -1
- package/lib/public/assets/runbook-page-DJDjeopU.js +253 -0
- package/lib/public/assets/{select-DvCSv25z.js → select-Bpyn7rWO.js} +1 -1
- package/lib/public/assets/{selector-detail-redirect-BLVfMJs_.js → selector-detail-redirect-BH74vmKv.js} +1 -1
- package/lib/public/assets/{selector-health-page-oqadRokn.js → selector-health-page-Cw_g218H.js} +2 -2
- package/lib/public/assets/session-detail-page-AZJE6XXE.js +4 -0
- package/lib/public/assets/settings-C3uyGhyc.js +6 -0
- package/lib/public/assets/{settings-Dep_3kbA.css → settings-K8UHWMdI.css} +1 -1
- package/lib/public/assets/{stat-tile-DV9Ix-4O.js → stat-tile-xVqAKIlI.js} +1 -1
- package/lib/public/assets/{tablet-6b_SEN2X.js → tablet-BxUScAeO.js} +1 -1
- package/lib/public/assets/{teams-BjZyfuHh.js → teams-B5ljGkY2.js} +1 -1
- package/lib/public/assets/{trash-2-CTZpPSdd.js → trash-2-B701i8sy.js} +1 -1
- package/lib/public/assets/{upload-P3XzwQUb.js → upload-C2gr44RS.js} +1 -1
- package/lib/public/assets/{use-builds-data-1cOCMf-z.js → use-builds-data-NeQOFEoy.js} +1 -1
- package/lib/public/assets/{use-password-reset-mode-DgF9w088.js → use-password-reset-mode-DEzJq5ef.js} +1 -1
- package/lib/public/assets/{users-DMF9Mk5H.js → users-D_vv_yz4.js} +1 -1
- package/lib/public/assets/{users-CiNTKUiz.js → users-MY6eNe6s.js} +1 -1
- package/lib/public/assets/{video-off-CHp1KU_T.js → video-off-OK1lNZQn.js} +1 -1
- package/lib/public/assets/webhook-settings-BU-C9lBf.js +1 -0
- package/lib/public/assets/{zap-DRz0tDq5.js → zap-DO9ry1iz.js} +1 -1
- package/lib/public/index.html +1 -1
- package/lib/schema.json +23 -25
- package/lib/src/XenonCapabilityManager.js +22 -5
- package/lib/src/app/dashboardPluginLink.js +117 -0
- package/lib/src/app/index.js +13 -34
- package/lib/src/app/openapi/control.yaml +73 -20
- package/lib/src/app/openapi/grid.yaml +31 -7
- package/lib/src/app/openapi/identity.yaml +103 -31
- package/lib/src/app/openapi/platform.yaml +165 -39
- package/lib/src/app/openapi/sessions.yaml +10 -3
- package/lib/src/app/routers/apikeys.js +14 -2
- package/lib/src/app/routers/auth.js +29 -5
- package/lib/src/app/routers/control.js +20 -2
- package/lib/src/app/routers/dashboard.js +69 -26
- package/lib/src/app/routers/grid.js +37 -13
- package/lib/src/app/routers/profile.js +21 -0
- package/lib/src/app/routers/streamType.js +7 -2
- package/lib/src/app/routers/users.js +10 -5
- package/lib/src/app/routers/webhook.js +8 -4
- package/lib/src/app/swagger.js +2 -0
- package/lib/src/app/ws/h264StreamWs.js +10 -1
- package/lib/src/config.js +51 -5
- package/lib/src/dashboard/commands.js +185 -141
- package/lib/src/dashboard/event-manager.js +88 -67
- package/lib/src/dashboard/services/failure-analysis-service.js +136 -45
- package/lib/src/dashboard/sessionCommandSummary.js +39 -0
- package/lib/src/data-service/appleFamily.js +43 -0
- package/lib/src/data-service/db.js +11 -0
- package/lib/src/data-service/device-service.js +6 -1
- package/lib/src/data-service/device-store.js +76 -3
- package/lib/src/data-service/deviceClaims.js +37 -0
- package/lib/src/data-service/deviceFieldOwners.js +25 -11
- package/lib/src/data-service/deviceSettings.js +79 -0
- package/lib/src/data-service/prisma-store.js +169 -15
- package/lib/src/data-service/web-config-service.js +50 -92
- package/lib/src/device-managers/AndroidDeviceManager.js +9 -31
- package/lib/src/device-managers/android/AndroidH264StreamService.js +69 -20
- package/lib/src/device-managers/android/H264Multiplexer.js +38 -4
- package/lib/src/device-managers/ios/WDAClient.js +44 -43
- package/lib/src/device-managers/shellCommands.js +96 -0
- package/lib/src/device-utils.js +114 -40
- package/lib/src/gateway/defaultGateway.js +1 -1
- package/lib/src/gateway/forwardToNode.js +2 -0
- package/lib/src/gateway/healReport.js +87 -0
- package/lib/src/gateway/sessionGateway.js +12 -2
- package/lib/src/generated/client/edge.js +18 -3
- package/lib/src/generated/client/index-browser.js +15 -0
- package/lib/src/generated/client/index.d.ts +2086 -379
- package/lib/src/generated/client/index.js +18 -3
- package/lib/src/generated/client/package.json +1 -1
- package/lib/src/generated/client/schema.prisma +38 -7
- package/lib/src/generated/client/wasm.js +15 -0
- package/lib/src/interceptors/CommandInterceptor.js +271 -188
- package/lib/src/interceptors/xenonScripts.js +55 -0
- package/lib/src/interfaces/IPluginArgs.js +1 -2
- package/lib/src/middleware/authMiddleware.js +15 -3
- package/lib/src/middleware/commandCaller.js +3 -3
- package/lib/src/middleware/verifyCredential.js +58 -1
- package/lib/src/plugin.js +23 -4
- package/lib/src/prisma.js +1 -1
- package/lib/src/scripts/database-check.js +124 -0
- package/lib/src/services/AICommandService.js +9 -2
- package/lib/src/services/AIService.js +281 -32
- package/lib/src/services/CleanupService.js +6 -1
- package/lib/src/services/EmailService.js +29 -0
- package/lib/src/services/InterceptorService.js +70 -13
- package/lib/src/services/NetworkConditioningService.js +85 -88
- package/lib/src/services/NotificationService.js +36 -29
- package/lib/src/services/OrphanSweeper.js +7 -0
- package/lib/src/services/PortAllocator.js +5 -0
- package/lib/src/services/SelectorVerificationJob.js +15 -4
- package/lib/src/services/ServerManager.js +105 -9
- package/lib/src/services/SessionLifecycleService.js +133 -75
- package/lib/src/services/ShutdownCoordinator.js +33 -0
- package/lib/src/services/SocketServer.js +19 -3
- package/lib/src/services/TeamService.js +20 -3
- package/lib/src/services/bug-report/video-slice.js +4 -1
- package/lib/src/services/device-access/leaseOverride.js +7 -5
- package/lib/src/services/healing/FuzzyXmlHealingProvider.js +51 -0
- package/lib/src/services/healing/HealEtalonService.js +3 -2
- package/lib/src/services/healing/HealingOrchestrator.js +85 -71
- package/lib/src/services/healing/OcrHealingProvider.js +41 -64
- package/lib/src/services/healing/ResilioTreeHealingProvider.js +41 -50
- package/lib/src/services/healing/VisualAiHealingProvider.js +1 -1
- package/lib/src/services/healing/fingerprintIdentity.js +126 -0
- package/lib/src/services/healing/resilioPath.js +274 -0
- package/lib/src/services/interceptor/AndroidProxyAdapter.js +18 -0
- package/lib/src/services/interceptor/interceptorOptions.js +44 -0
- package/lib/src/services/logcat/SessionDeviceLogs.js +271 -0
- package/lib/src/services/logcat/deviceLogBook.js +163 -0
- package/lib/src/services/network/AndroidRadios.js +71 -0
- package/lib/src/services/network/PhoneNetworkLedger.js +184 -0
- package/lib/src/services/network/PhoneNetworkRestore.js +330 -0
- package/lib/src/services/network/adbForPhone.js +60 -0
- package/lib/src/services/network/phoneNetworkLock.js +20 -0
- package/lib/src/services/network/xenonProxy.js +107 -0
- package/lib/src/services/ocr/ocrData.js +118 -0
- package/lib/src/services/ocr/vendor/LICENSE-tessdata.txt +202 -0
- package/lib/src/services/ocr/vendor/eng.traineddata.gz +0 -0
- package/lib/src/services/omni-vision/OmniVisionService.js +132 -95
- package/lib/src/services/omni-vision/VisionAssertionService.js +28 -25
- package/lib/src/services/omni-vision/ocrTextMatch.js +105 -0
- package/lib/src/services/omni-vision/screenScale.js +68 -0
- package/lib/src/services/passwordResetLink.js +50 -9
- package/lib/src/services/passwordResetMode.js +3 -1
- package/lib/src/services/publicUrl.js +45 -0
- package/lib/src/services/recording/concurrency-gate.js +12 -3
- package/lib/src/services/session/sessionIdentity.js +5 -3
- package/lib/src/services/session/shutdownReason.js +26 -0
- package/lib/src/services/settings/SelfHealingSwitch.js +70 -0
- package/lib/src/services/settings/aiEngineSettings.js +219 -0
- package/lib/src/services/settings/labSettings.js +149 -0
- package/lib/src/services/token/mintedLifetime.js +51 -0
- package/lib/src/services/webhookEvents.js +173 -0
- package/lib/src/sessions/SessionManager.js +8 -2
- package/lib/src/sessions/sessionMemory.js +25 -0
- package/lib/test/helpers/fake-adb.js +58 -0
- package/lib/test/helpers/fake-ai-provider.js +188 -0
- package/lib/test/helpers/fake-device-table.js +63 -24
- package/lib/test/helpers/loki-stores.js +33 -0
- package/lib/test/helpers/page-sources.js +164 -0
- package/lib/test/helpers/scratch-database.js +58 -13
- package/lib/test/integration/audit-ingest.spec.js +10 -10
- package/lib/test/integration/auth-flow.spec.js +9 -14
- package/lib/test/integration/auth-rate-limit.spec.js +6 -3
- package/lib/test/integration/bug-report-route.spec.js +22 -2
- package/lib/test/integration/forgot-password-rate-limit.spec.js +6 -3
- package/lib/test/integration/forgot-password.spec.js +17 -18
- package/lib/test/integration/legacy-deprecation-headers.spec.js +5 -2
- package/lib/test/integration/migration.spec.js +6 -1
- package/lib/test/integration/node-pair-auth-rest.spec.js +5 -9
- package/lib/test/integration/ports-router.spec.js +4 -4
- package/lib/test/integration/prisma-device-store-add-devices.spec.js +2 -3
- package/lib/test/integration/prisma-device-store-team-filter.spec.js +2 -5
- package/lib/test/integration/profile-tokens.spec.js +10 -16
- package/lib/test/integration/recordings-router.spec.js +16 -16
- package/lib/test/integration/reset-revokes-sessions.spec.js +4 -9
- package/lib/test/integration/role-matrix.spec.js +4 -9
- package/lib/test/integration/sdk-leases-router.spec.js +9 -9
- package/lib/test/integration/sdk-version.spec.js +2 -2
- package/lib/test/integration/selector-health-endpoint.spec.js +5 -5
- package/lib/test/integration/team-membership-migration.spec.js +73 -12
- package/lib/test/integration/team-visibility-apps.spec.js +15 -22
- package/lib/test/integration/team-visibility-control.spec.js +96 -69
- package/lib/test/integration/team-visibility-dashboard.spec.js +7 -23
- package/lib/test/integration/team-visibility-grid.spec.js +16 -15
- package/lib/test/integration/team-visibility-leases.spec.js +8 -11
- package/lib/test/integration/team-visibility-recordings.spec.js +6 -19
- package/lib/test/integration/team-visibility-sessions.spec.js +6 -19
- package/lib/test/integration/users-flow.spec.js +7 -12
- package/lib/test/integration/users-lockout.spec.js +5 -3
- package/lib/test/unit/EmailService.test.js +66 -0
- package/lib/test/unit/ResilioTreeHealingProvider.test.js +46 -19
- package/lib/test/unit/TeamService.test.js +3 -0
- package/lib/test/unit/XenonCapabilityManager.spec.js +4 -2
- package/lib/test/unit/ai-call-time-limit.spec.js +130 -0
- package/lib/test/unit/ai-engine-settings.spec.js +338 -0
- package/lib/test/unit/ai-provider-switch.spec.js +130 -0
- package/lib/test/unit/ai-rate-limit.spec.js +126 -0
- package/lib/test/unit/android-h264-viewers.spec.js +272 -0
- package/lib/test/unit/android-preview-hold.spec.js +3 -2
- package/lib/test/unit/apikeys-router.spec.js +84 -0
- package/lib/test/unit/apple-family.spec.js +36 -0
- package/lib/test/unit/authMiddleware.bearer.spec.js +9 -0
- package/lib/test/unit/authMiddleware.credentialLifetime.spec.js +149 -0
- package/lib/test/unit/bug-report/video-slice.spec.js +19 -0
- package/lib/test/unit/cleanup-settings-db.spec.js +103 -0
- package/lib/test/unit/cleanup-settings.spec.js +244 -0
- package/lib/test/unit/dashboard-api-paths.spec.js +101 -0
- package/lib/test/unit/dashboard-commands.spec.js +249 -0
- package/lib/test/unit/dashboard-events-device-logs.spec.js +207 -0
- package/lib/test/unit/dashboard-events-team-scope.spec.js +9 -6
- package/lib/test/unit/dashboard-plugin-link.spec.js +213 -0
- package/lib/test/unit/database-check.spec.js +108 -0
- package/lib/test/unit/default-plugin-args.spec.js +33 -0
- package/lib/test/unit/device-log-book.spec.js +180 -0
- package/lib/test/unit/device-offline-webhook.spec.js +81 -0
- package/lib/test/unit/device-setting-columns.spec.js +66 -0
- package/lib/test/unit/device-settings-loki.spec.js +87 -0
- package/lib/test/unit/device-settings-survive.spec.js +555 -0
- package/lib/test/unit/device-sync-lost-update.spec.js +5 -0
- package/lib/test/unit/emulator-boot.spec.js +91 -0
- package/lib/test/unit/enable-dashboard-option.spec.js +57 -0
- package/lib/test/unit/event-log-session-data.spec.js +244 -0
- package/lib/test/unit/failure-analysis.spec.js +182 -0
- package/lib/test/unit/failure-categories.spec.js +128 -0
- package/lib/test/unit/fingerprint-identity.spec.js +433 -0
- package/lib/test/unit/h264-multiplexer.spec.js +46 -0
- package/lib/test/unit/heal-report.spec.js +71 -0
- package/lib/test/unit/healing-instrumentation.spec.js +6 -1
- package/lib/test/unit/healing-tier-gate.spec.js +73 -29
- package/lib/test/unit/healing-tiers-every-session.spec.js +219 -0
- package/lib/test/unit/hub-node-gateway-appium-server.spec.js +219 -0
- package/lib/test/unit/hub-node-same-host.spec.js +5 -0
- package/lib/test/unit/interceptor-visual-elements.spec.js +192 -0
- package/lib/test/unit/iphone-ipad-only.spec.js +132 -0
- package/lib/test/unit/json-logging-option.spec.js +74 -0
- package/lib/test/unit/lab-settings.spec.js +218 -0
- package/lib/test/unit/lease/lease-override.spec.js +23 -6
- package/lib/test/unit/lease/session-lease-proof.spec.js +16 -4
- package/lib/test/unit/max-sessions.spec.js +240 -0
- package/lib/test/unit/ocr-healing-tier-real-ocr.spec.js +113 -0
- package/lib/test/unit/ocr-healing-tier.spec.js +122 -0
- package/lib/test/unit/ocr-offline.spec.js +213 -0
- package/lib/test/unit/ocr-text-match.spec.js +44 -0
- package/lib/test/unit/omni-virtual-element-store.spec.js +301 -0
- package/lib/test/unit/omni-vision-analyze-screen.spec.js +72 -0
- package/lib/test/unit/omni-vision-ios-points.spec.js +159 -0
- package/lib/test/unit/omni-vision-tap-text.spec.js +129 -0
- package/lib/test/unit/omni-vision.spec.js +6 -8
- package/lib/test/unit/package-engines.spec.js +27 -0
- package/lib/test/unit/partial-config-file.spec.js +14 -0
- package/lib/test/unit/passwordResetMode.test.js +10 -2
- package/lib/test/unit/phone-network/boot-clean-up.spec.js +64 -0
- package/lib/test/unit/phone-network/interceptor-options.spec.js +77 -0
- package/lib/test/unit/phone-network/interceptor-proxy-restore.spec.js +145 -0
- package/lib/test/unit/phone-network/network-conditioning.spec.js +145 -0
- package/lib/test/unit/phone-network/phone-network-restore.spec.js +246 -0
- package/lib/test/unit/phone-network/session-end-paths.spec.js +182 -0
- package/lib/test/unit/phone-network/session-start.spec.js +110 -0
- package/lib/test/unit/phone-network/xenon-proxy.spec.js +69 -0
- package/lib/test/unit/plugin.spec.js +3 -3
- package/lib/test/unit/profile-router.test.js +122 -1
- package/lib/test/unit/queue-requester.spec.js +1 -1
- package/lib/test/unit/recording-options.spec.js +181 -0
- package/lib/test/unit/reset-link-address.spec.js +266 -0
- package/lib/test/unit/reset-link.test.js +10 -4
- package/lib/test/unit/resilio-path-healing.spec.js +270 -0
- package/lib/test/unit/selector-learning-every-session.spec.js +179 -0
- package/lib/test/unit/selector-verification-clean-build.spec.js +130 -0
- package/lib/test/unit/selector-verification-job.spec.js +13 -13
- package/lib/test/unit/self-healing-boot.spec.js +80 -0
- package/lib/test/unit/self-healing-setting.spec.js +273 -0
- package/lib/test/unit/session-app-resolution.spec.js +5 -1
- package/lib/test/unit/session-attribution-wiring.spec.js +41 -13
- package/lib/test/unit/session-create-credential-owner.spec.js +242 -0
- package/lib/test/unit/session-credential-strip.spec.js +1 -1
- package/lib/test/unit/session-device-logs.spec.js +347 -0
- package/lib/test/unit/session-end-failure-analysis.spec.js +133 -0
- package/lib/test/unit/session-failed-webhook.spec.js +170 -0
- package/lib/test/unit/session-log-indexes.spec.js +64 -3
- package/lib/test/unit/shell-commands.spec.js +133 -0
- package/lib/test/unit/socketServer.scopedEmit.spec.js +2 -0
- package/lib/test/unit/socketServer.sessionCookie.spec.js +2 -1
- package/lib/test/unit/stream-start-pipelines.spec.js +264 -0
- package/lib/test/unit/stream-status-type.spec.js +4 -0
- package/lib/test/unit/token-mint-limits.spec.js +165 -0
- package/lib/test/unit/unexpected-shutdown-reason.spec.js +163 -0
- package/lib/test/unit/verify-credential.spec.js +33 -0
- package/lib/test/unit/vision-assertion.spec.js +119 -0
- package/lib/test/unit/wda-client-shell.spec.js +133 -0
- package/lib/test/unit/web-config-service.spec.js +98 -0
- package/lib/test/unit/webhook-delivery.spec.js +24 -0
- package/lib/test/unit/webhook-payloads.spec.js +273 -0
- package/lib/test/unit/xenon-execute-scripts.spec.js +138 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/web/src/components/webhook-settings/webhookEventVariables.json +30 -0
- package/package.json +5 -5
- package/prisma/migrations/20261004140000_keep_device_settings/migration.sql +19 -0
- package/prisma/migrations/20261004174413_locator_etalon_path/migration.sql +2 -0
- package/prisma/schema.prisma +38 -7
- package/schema.json +23 -25
- package/scripts/generate-types-from-schema.js +1 -2
- package/scripts/lib/always-present-plugin-args.js +4 -1
- package/lib/public/assets/BugReportButton-BoGhlI7F.js +0 -15
- package/lib/public/assets/DeviceMosaicView-8J0oYqMM.js +0 -2
- package/lib/public/assets/ai-settings-Bce5SJob.js +0 -21
- package/lib/public/assets/device-explorer-C-KnhMHI.js +0 -279
- package/lib/public/assets/forgot-password-DnudqFFo.js +0 -1
- package/lib/public/assets/maintenance-settings-zDVlOMVK.js +0 -6
- package/lib/public/assets/recording-group-store-WVM3hoXn.js +0 -26
- package/lib/public/assets/runbook-page-DJTVCJX7.js +0 -124
- package/lib/public/assets/session-detail-page-CGn55Pvl.js +0 -4
- package/lib/public/assets/settings-MsVU2ukE.js +0 -6
- package/lib/public/assets/webhook-settings-DiS8geIm.js +0 -1
- /package/lib/public/assets/{BugReportButton-CPBjfiv4.css → index-CPBjfiv4.css} +0 -0
|
@@ -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
|
|
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,
|
|
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,
|
|
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
|
|
60
|
-
(0, chai_1.expect)(
|
|
61
|
-
const reset = yield (0,
|
|
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 (
|
|
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,
|
|
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,
|
|
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 (
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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);
|
|
@@ -16,7 +16,7 @@ require("reflect-metadata");
|
|
|
16
16
|
const chai_1 = require("chai");
|
|
17
17
|
const sinon_1 = __importDefault(require("sinon"));
|
|
18
18
|
const express_1 = __importDefault(require("express"));
|
|
19
|
-
const
|
|
19
|
+
const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
|
|
20
20
|
const typedi_1 = require("typedi");
|
|
21
21
|
const recordings_1 = __importDefault(require("../../src/app/routers/recordings"));
|
|
22
22
|
const authMiddleware_1 = require("../../src/middleware/authMiddleware");
|
|
@@ -76,7 +76,7 @@ describe('Recordings router (integration)', () => {
|
|
|
76
76
|
startedAt: new Date(),
|
|
77
77
|
compositeEnabled: false,
|
|
78
78
|
});
|
|
79
|
-
const r = yield (0,
|
|
79
|
+
const r = yield (0, loopbackRequest_1.default)(makeApp())
|
|
80
80
|
.post('/xenon/api/recordings')
|
|
81
81
|
.send({ udids: ['U1'] });
|
|
82
82
|
(0, chai_1.expect)(r.status).to.equal(202);
|
|
@@ -88,7 +88,7 @@ describe('Recordings router (integration)', () => {
|
|
|
88
88
|
.rejects(new RecordingOrchestrator_1.RecordingError('device_busy', [
|
|
89
89
|
{ udid: 'U2', reason: 'automation', sessionId: 'sess-x' },
|
|
90
90
|
]));
|
|
91
|
-
const r = yield (0,
|
|
91
|
+
const r = yield (0, loopbackRequest_1.default)(makeApp())
|
|
92
92
|
.post('/xenon/api/recordings')
|
|
93
93
|
.send({ udids: ['U1', 'U2'] });
|
|
94
94
|
(0, chai_1.expect)(r.status).to.equal(409);
|
|
@@ -101,7 +101,7 @@ describe('Recordings router (integration)', () => {
|
|
|
101
101
|
sinon_1.default
|
|
102
102
|
.stub(typedi_1.Container.get(RecordingOrchestrator_1.RecordingOrchestrator), 'start')
|
|
103
103
|
.rejects(new RecordingOrchestrator_1.RecordingError('concurrency_cap', undefined, 4, 4));
|
|
104
|
-
const r = yield (0,
|
|
104
|
+
const r = yield (0, loopbackRequest_1.default)(makeApp())
|
|
105
105
|
.post('/xenon/api/recordings')
|
|
106
106
|
.send({ udids: ['U1'] });
|
|
107
107
|
(0, chai_1.expect)(r.status).to.equal(409);
|
|
@@ -109,16 +109,16 @@ describe('Recordings router (integration)', () => {
|
|
|
109
109
|
}));
|
|
110
110
|
it('POST /recordings: 400 when udids missing or empty', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
111
111
|
const app = makeApp();
|
|
112
|
-
yield (0,
|
|
113
|
-
yield (0,
|
|
114
|
-
yield (0,
|
|
112
|
+
yield (0, loopbackRequest_1.default)(app).post('/xenon/api/recordings').send({}).expect(400);
|
|
113
|
+
yield (0, loopbackRequest_1.default)(app).post('/xenon/api/recordings').send({ udids: [] }).expect(400);
|
|
114
|
+
yield (0, loopbackRequest_1.default)(app).post('/xenon/api/recordings').send({ udids: [123] }).expect(400);
|
|
115
115
|
}));
|
|
116
116
|
it('POST /recordings/:groupId/stop: 200', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
117
117
|
sinon_1.default.stub(typedi_1.Container.get(RecordingOrchestrator_1.RecordingOrchestrator), 'stop').resolves({
|
|
118
118
|
groupId: 'g-1',
|
|
119
119
|
recordings: [{ id: 'r-1', udid: 'U1', status: 'STOPPED', durationMs: 5000, sizeBytes: 1024 }],
|
|
120
120
|
});
|
|
121
|
-
const r = yield (0,
|
|
121
|
+
const r = yield (0, loopbackRequest_1.default)(makeApp()).post('/xenon/api/recordings/g-1/stop');
|
|
122
122
|
(0, chai_1.expect)(r.status).to.equal(200);
|
|
123
123
|
(0, chai_1.expect)(r.body.recordings[0].status).to.equal('STOPPED');
|
|
124
124
|
}));
|
|
@@ -127,11 +127,11 @@ describe('Recordings router (integration)', () => {
|
|
|
127
127
|
sinon_1.default
|
|
128
128
|
.stub(typedi_1.Container.get(RecordingOrchestrator_1.RecordingOrchestrator), 'addBookmark')
|
|
129
129
|
.resolves({ id: 'bm-1', label: 'bug here' });
|
|
130
|
-
const ok = yield (0,
|
|
130
|
+
const ok = yield (0, loopbackRequest_1.default)(makeApp())
|
|
131
131
|
.post('/xenon/api/recordings/g-1/bookmark')
|
|
132
132
|
.send({ recordingId: 'r-1', timecodeMs: 1000, label: 'bug here' });
|
|
133
133
|
(0, chai_1.expect)(ok.status).to.equal(201);
|
|
134
|
-
const bad = yield (0,
|
|
134
|
+
const bad = yield (0, loopbackRequest_1.default)(makeApp())
|
|
135
135
|
.post('/xenon/api/recordings/g-1/bookmark')
|
|
136
136
|
.send({ timecodeMs: 1000 });
|
|
137
137
|
(0, chai_1.expect)(bad.status).to.equal(400);
|
|
@@ -166,7 +166,7 @@ describe('Recordings router (integration)', () => {
|
|
|
166
166
|
startedAt: new Date(),
|
|
167
167
|
compositeEnabled: false,
|
|
168
168
|
});
|
|
169
|
-
const r = yield (0,
|
|
169
|
+
const r = yield (0, loopbackRequest_1.default)(makeBearerApp())
|
|
170
170
|
.post('/xenon/api/recordings')
|
|
171
171
|
.send({ udids: ['U1'] });
|
|
172
172
|
(0, chai_1.expect)(r.status).to.equal(202);
|
|
@@ -176,7 +176,7 @@ describe('Recordings router (integration)', () => {
|
|
|
176
176
|
groupId: 'g-1',
|
|
177
177
|
recordings: [{ id: 'r-2', udid: 'U2', status: 'RECORDING' }],
|
|
178
178
|
});
|
|
179
|
-
const r = yield (0,
|
|
179
|
+
const r = yield (0, loopbackRequest_1.default)(makeBearerApp())
|
|
180
180
|
.post('/xenon/api/recordings/g-1/add-device')
|
|
181
181
|
.send({ udid: 'U2' });
|
|
182
182
|
(0, chai_1.expect)(r.status).to.equal(201);
|
|
@@ -215,7 +215,7 @@ describe('Recordings router (integration)', () => {
|
|
|
215
215
|
startedAt: new Date(),
|
|
216
216
|
compositeEnabled: false,
|
|
217
217
|
});
|
|
218
|
-
const r = yield (0,
|
|
218
|
+
const r = yield (0, loopbackRequest_1.default)(makeHeaderPairApp())
|
|
219
219
|
.post('/xenon/api/recordings')
|
|
220
220
|
.send({ udids: ['U1'] });
|
|
221
221
|
(0, chai_1.expect)(r.status).to.equal(202);
|
|
@@ -227,7 +227,7 @@ describe('Recordings router (integration)', () => {
|
|
|
227
227
|
groupId: 'g-1',
|
|
228
228
|
recordings: [{ id: 'r-2', udid: 'U2', status: 'RECORDING' }],
|
|
229
229
|
});
|
|
230
|
-
const r = yield (0,
|
|
230
|
+
const r = yield (0, loopbackRequest_1.default)(makeHeaderPairApp())
|
|
231
231
|
.post('/xenon/api/recordings/g-1/add-device')
|
|
232
232
|
.send({ udid: 'U2' });
|
|
233
233
|
(0, chai_1.expect)(r.status).to.equal(201);
|
|
@@ -239,7 +239,7 @@ describe('Recordings router (integration)', () => {
|
|
|
239
239
|
sinon_1.default
|
|
240
240
|
.stub(typedi_1.Container.get(RecordingOrchestrator_1.RecordingOrchestrator), 'addAnnotation')
|
|
241
241
|
.resolves({ id: 'an-1' });
|
|
242
|
-
const ok = yield (0,
|
|
242
|
+
const ok = yield (0, loopbackRequest_1.default)(makeApp())
|
|
243
243
|
.post('/xenon/api/recordings/g-1/annotation')
|
|
244
244
|
.send({
|
|
245
245
|
recordingId: 'r-1',
|
|
@@ -249,7 +249,7 @@ describe('Recordings router (integration)', () => {
|
|
|
249
249
|
color: '#ff0000',
|
|
250
250
|
});
|
|
251
251
|
(0, chai_1.expect)(ok.status).to.equal(201);
|
|
252
|
-
const bad = yield (0,
|
|
252
|
+
const bad = yield (0, loopbackRequest_1.default)(makeApp())
|
|
253
253
|
.post('/xenon/api/recordings/g-1/annotation')
|
|
254
254
|
.send({ shape: 'RECT' });
|
|
255
255
|
(0, chai_1.expect)(bad.status).to.equal(400);
|
|
@@ -15,20 +15,20 @@ 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
|
|
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 UserSessionService_1 = require("../../src/services/UserSessionService");
|
|
23
23
|
const PasswordResetService_1 = require("../../src/services/PasswordResetService");
|
|
24
24
|
const prisma_1 = require("../../src/prisma");
|
|
25
|
+
const scratch_database_1 = require("../helpers/scratch-database");
|
|
25
26
|
describe('reset-password revokes all sessions', function () {
|
|
26
27
|
this.timeout(30000);
|
|
28
|
+
(0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
|
|
27
29
|
const email = 'reset-revokes-it@xenon.local';
|
|
28
30
|
let user;
|
|
29
31
|
before(() => __awaiter(this, void 0, void 0, function* () {
|
|
30
|
-
yield prisma_1.prisma.userSession.deleteMany({ where: { user: { email } } });
|
|
31
|
-
yield prisma_1.prisma.user.deleteMany({ where: { email } });
|
|
32
32
|
user = yield typedi_1.Container.get(UserService_1.UserService).createUser({
|
|
33
33
|
email,
|
|
34
34
|
name: 'Reset Revokes IT',
|
|
@@ -36,11 +36,6 @@ describe('reset-password revokes all sessions', function () {
|
|
|
36
36
|
role: 'MEMBER',
|
|
37
37
|
});
|
|
38
38
|
}));
|
|
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
39
|
it('deletes every UserSession for the resetting user', () => __awaiter(this, void 0, void 0, function* () {
|
|
45
40
|
const sessions = [
|
|
46
41
|
yield typedi_1.Container.get(UserSessionService_1.UserSessionService).create(user.id),
|
|
@@ -51,7 +46,7 @@ describe('reset-password revokes all sessions', function () {
|
|
|
51
46
|
const app = (0, express_1.default)();
|
|
52
47
|
app.use(express_1.default.json());
|
|
53
48
|
app.use('/auth', (0, auth_1.authPublicRouter)());
|
|
54
|
-
const r = yield (0,
|
|
49
|
+
const r = yield (0, loopbackRequest_1.default)(app)
|
|
55
50
|
.post('/auth/reset-password')
|
|
56
51
|
.send({ token: raw, newPassword: 'BrandNewPw1' });
|
|
57
52
|
(0, chai_1.expect)(r.status).to.equal(204);
|
|
@@ -15,13 +15,13 @@ 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
|
|
18
|
+
const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
|
|
19
19
|
const authMiddleware_1 = require("../../src/middleware/authMiddleware");
|
|
20
20
|
const apikeys_1 = require("../../src/app/routers/apikeys");
|
|
21
21
|
const teams_1 = require("../../src/app/routers/teams");
|
|
22
22
|
const processes_1 = require("../../src/app/routers/processes");
|
|
23
23
|
const users_1 = require("../../src/app/routers/users");
|
|
24
|
-
const
|
|
24
|
+
const scratch_database_1 = require("../helpers/scratch-database");
|
|
25
25
|
const seedUser_1 = require("../helpers/seedUser");
|
|
26
26
|
// scopesForRole now grants ADMIN the full 'admin,devices,sessions,read' set on
|
|
27
27
|
// cookie sessions (the user themselves logged in via /login). Token-default
|
|
@@ -84,6 +84,7 @@ function buildApp() {
|
|
|
84
84
|
}
|
|
85
85
|
describe('role matrix (integration)', function () {
|
|
86
86
|
this.timeout(60000);
|
|
87
|
+
(0, scratch_database_1.useScratchDatabase)({ wholeSuite: true });
|
|
87
88
|
let users;
|
|
88
89
|
before(() => __awaiter(this, void 0, void 0, function* () {
|
|
89
90
|
users = {
|
|
@@ -92,18 +93,12 @@ describe('role matrix (integration)', function () {
|
|
|
92
93
|
MEMBER: yield (0, seedUser_1.seedUser)('MEMBER'),
|
|
93
94
|
};
|
|
94
95
|
}));
|
|
95
|
-
after(() => __awaiter(this, void 0, void 0, function* () {
|
|
96
|
-
yield users.SUPER_ADMIN.cleanup();
|
|
97
|
-
yield users.ADMIN.cleanup();
|
|
98
|
-
yield users.MEMBER.cleanup();
|
|
99
|
-
yield prisma_1.prisma.user.deleteMany({ where: { email: { contains: 'rmcase-' } } });
|
|
100
|
-
}));
|
|
101
96
|
CASES.forEach((c) => {
|
|
102
97
|
['SUPER_ADMIN', 'ADMIN', 'MEMBER'].forEach((role) => {
|
|
103
98
|
it(`${role} ${c.method} ${c.path} → expect ${c.expect[role]}`, () => __awaiter(this, void 0, void 0, function* () {
|
|
104
99
|
const app = buildApp();
|
|
105
100
|
const expected = c.expect[role];
|
|
106
|
-
const reqBuilder = (0,
|
|
101
|
+
const reqBuilder = (0, loopbackRequest_1.default)(app)[c.method.toLowerCase()](c.path).set('Cookie', users[role].cookie);
|
|
107
102
|
const body = typeof c.body === 'function' ? c.body() : c.body;
|
|
108
103
|
const r = body ? yield reqBuilder.send(body) : yield reqBuilder;
|
|
109
104
|
if (expected >= 200 && expected < 300) {
|
|
@@ -15,7 +15,7 @@ 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
|
|
18
|
+
const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
|
|
19
19
|
const sinon_1 = __importDefault(require("sinon"));
|
|
20
20
|
// Static imports (recordings-router.spec idiom): the previous extensionless
|
|
21
21
|
// dynamic `await import(...)` fails to resolve when Node's native ESM loader
|
|
@@ -53,7 +53,7 @@ describe('POST /xenon/api/sdk/leases', () => {
|
|
|
53
53
|
allocatedPorts: { systemPort: 9001 },
|
|
54
54
|
appiumCapabilities: { 'appium:udid': 'u1', 'xe:options': { leaseId: 'lse_1' } },
|
|
55
55
|
});
|
|
56
|
-
const res = yield (0,
|
|
56
|
+
const res = yield (0, loopbackRequest_1.default)(app)
|
|
57
57
|
.post('/xenon/api/sdk/leases')
|
|
58
58
|
.send({ filters: { platform: 'android' }, durationMs: 60000, heartbeatSeconds: 30 });
|
|
59
59
|
(0, chai_1.expect)(res.status).to.equal(201);
|
|
@@ -62,7 +62,7 @@ describe('POST /xenon/api/sdk/leases', () => {
|
|
|
62
62
|
}));
|
|
63
63
|
it('records the api-key principal as actor/team on create', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
64
64
|
leaseSvc.create.resolves({ leaseId: 'lse_1', leaseToken: 't'.repeat(64) });
|
|
65
|
-
yield (0,
|
|
65
|
+
yield (0, loopbackRequest_1.default)(app)
|
|
66
66
|
.post('/xenon/api/sdk/leases')
|
|
67
67
|
.send({ filters: { platform: 'android' } });
|
|
68
68
|
(0, chai_1.expect)(leaseSvc.create.calledOnce).to.equal(true);
|
|
@@ -91,7 +91,7 @@ describe('POST /xenon/api/sdk/leases', () => {
|
|
|
91
91
|
});
|
|
92
92
|
bearerApp.use('/xenon/api/sdk/leases', (0, sdk_leases_1.makeRouter)({ leaseService: leaseSvc }));
|
|
93
93
|
leaseSvc.create.resolves({ leaseId: 'lse_2', leaseToken: 't'.repeat(64) });
|
|
94
|
-
const res = yield (0,
|
|
94
|
+
const res = yield (0, loopbackRequest_1.default)(bearerApp)
|
|
95
95
|
.post('/xenon/api/sdk/leases')
|
|
96
96
|
.send({ filters: { platform: 'android' } });
|
|
97
97
|
(0, chai_1.expect)(res.status).to.equal(201);
|
|
@@ -103,7 +103,7 @@ describe('POST /xenon/api/sdk/leases', () => {
|
|
|
103
103
|
}));
|
|
104
104
|
it('returns 404 when no device matches', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
105
105
|
leaseSvc.create.rejects(new LeaseService_1.NoMatchingDevice('no device'));
|
|
106
|
-
const res = yield (0,
|
|
106
|
+
const res = yield (0, loopbackRequest_1.default)(app)
|
|
107
107
|
.post('/xenon/api/sdk/leases')
|
|
108
108
|
.send({ filters: { platform: 'android', udid: 'absent' }, durationMs: 60000 });
|
|
109
109
|
(0, chai_1.expect)(res.status).to.equal(404);
|
|
@@ -111,23 +111,23 @@ describe('POST /xenon/api/sdk/leases', () => {
|
|
|
111
111
|
}));
|
|
112
112
|
it('heartbeat: 200 with valid token; 403 without', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
113
113
|
leaseSvc.heartbeat.resolves({ heartbeatedAt: Date.now(), expiresAt: Date.now() + 60000 });
|
|
114
|
-
const res1 = yield (0,
|
|
114
|
+
const res1 = yield (0, loopbackRequest_1.default)(app)
|
|
115
115
|
.post('/xenon/api/sdk/leases/lse_1/heartbeat')
|
|
116
116
|
.set('x-xenon-lease-token', 'cleartext');
|
|
117
117
|
(0, chai_1.expect)(res1.status).to.equal(200);
|
|
118
|
-
const res2 = yield (0,
|
|
118
|
+
const res2 = yield (0, loopbackRequest_1.default)(app).post('/xenon/api/sdk/leases/lse_1/heartbeat');
|
|
119
119
|
(0, chai_1.expect)(res2.status).to.equal(403);
|
|
120
120
|
}));
|
|
121
121
|
it('heartbeat: 403 on token mismatch from service', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
122
122
|
leaseSvc.heartbeat.rejects(new LeaseService_1.LeaseTokenMismatch());
|
|
123
|
-
const res = yield (0,
|
|
123
|
+
const res = yield (0, loopbackRequest_1.default)(app)
|
|
124
124
|
.post('/xenon/api/sdk/leases/lse_1/heartbeat')
|
|
125
125
|
.set('x-xenon-lease-token', 'wrong');
|
|
126
126
|
(0, chai_1.expect)(res.status).to.equal(403);
|
|
127
127
|
}));
|
|
128
128
|
it('heartbeat: 410 Gone on expired lease', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
129
129
|
leaseSvc.heartbeat.rejects(new LeaseService_1.LeaseGone('expired'));
|
|
130
|
-
const res = yield (0,
|
|
130
|
+
const res = yield (0, loopbackRequest_1.default)(app)
|
|
131
131
|
.post('/xenon/api/sdk/leases/lse_1/heartbeat')
|
|
132
132
|
.set('x-xenon-lease-token', 'whatever');
|
|
133
133
|
(0, chai_1.expect)(res.status).to.equal(410);
|