@xenon-device-management/xenon 2.13.1 → 2.14.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 +11 -5
- package/lib/package.json +1 -1
- package/lib/public/assets/{AnnotationOverlay-Cvpkk4r9.js → AnnotationOverlay-B_VNtKBH.js} +1 -1
- package/lib/public/assets/{ApiKeyGate-Bhn5ZtVM.js → ApiKeyGate-BwuaMjkX.js} +1 -1
- package/lib/public/assets/{BugReportButton-BA6aEjTC.js → BugReportButton-BAt0_pzq.js} +1 -1
- package/lib/public/assets/DeviceMosaicView-BYaQHhTf.js +2 -0
- package/lib/public/assets/{EmptyState-CgzbuUvO.js → EmptyState-BSjhk_IV.js} +1 -1
- package/lib/public/assets/{FieldGroup-BHc_5qNc.js → FieldGroup-Cb5QZsE1.js} +1 -1
- package/lib/public/assets/{FilterMenu-D7OMGuRc.js → FilterMenu-BAaSlWbW.js} +1 -1
- package/lib/public/assets/{Menu-C173JJ0l.js → Menu-JGGYrSQQ.js} +1 -1
- package/lib/public/assets/{Modal-ChvVUI3B.js → Modal-CFCp3n9d.js} +1 -1
- package/lib/public/assets/{RecordingPage-Dhw4d_O6.js → RecordingPage-CbJj_EBT.js} +1 -1
- package/lib/public/assets/{RecordingsPage-z97ftGK-.js → RecordingsPage-BJeYnygR.js} +2 -2
- package/lib/public/assets/{SegmentedControl-DbXhBGZC.js → SegmentedControl-Bg42Atjy.js} +1 -1
- package/lib/public/assets/{SettingCard-C908GgiI.js → SettingCard-Njz1pUIJ.js} +1 -1
- package/lib/public/assets/{Table-B1DB_ZN-.js → Table-BcTm5xV2.js} +1 -1
- package/lib/public/assets/{activity-Css0xNvp.js → activity-DOVdsfMQ.js} +1 -1
- package/lib/public/assets/{ai-settings-BMQK3-yN.js → ai-settings-CsuJroRf.js} +2 -2
- package/lib/public/assets/{api-keys-CbJ42eDQ.js → api-keys-BKnNSTw9.js} +1 -1
- package/lib/public/assets/{apps-DW1pw2re.js → apps-D0SC6uw6.js} +2 -2
- package/lib/public/assets/{arrow-left-Dpog9L0F.js → arrow-left-MMbTmgoE.js} +1 -1
- package/lib/public/assets/{arrow-right-CsBIlSIw.js → arrow-right-BMfnGmxW.js} +1 -1
- package/lib/public/assets/{arrow-up-right-z1tRQE4R.js → arrow-up-right-DuAftMWB.js} +1 -1
- package/lib/public/assets/{auth-shell-mXiX5vNk.js → auth-shell-nZC2JNDO.js} +2 -2
- package/lib/public/assets/{builds-page-BcFn23bE.js → builds-page-hDCgTwkS.js} +1 -1
- package/lib/public/assets/{button-Cq_zHETv.js → button-Dda4irn_.js} +1 -1
- package/lib/public/assets/{calendar-CKxABX9q.js → calendar-BMr0Q62v.js} +1 -1
- package/lib/public/assets/{check-C7xu-hGU.js → check-CZ9iw9-e.js} +1 -1
- package/lib/public/assets/{chevron-right-BiqfdCGA.js → chevron-right-BRYJJVC9.js} +1 -1
- package/lib/public/assets/{circle-check-CyBjjPxR.js → circle-check-CqAJjQ5O.js} +1 -1
- package/lib/public/assets/{circle-x-6gMRcx6z.js → circle-x-DlDJtnVz.js} +1 -1
- package/lib/public/assets/{clock-U1rDTT1h.js → clock-CpuDKysU.js} +1 -1
- package/lib/public/assets/{copy-BIM0ZX0L.js → copy-CAQydNFe.js} +1 -1
- package/lib/public/assets/device-explorer-CdO6_nrn.js +282 -0
- package/lib/public/assets/{download-DDBRXnAZ.js → download-C9XG6lLv.js} +1 -1
- package/lib/public/assets/{forgot-password-Dpg7yxM8.js → forgot-password-CGnkRgE9.js} +1 -1
- package/lib/public/assets/h264Stream-VQBphYhg.js +26 -0
- package/lib/public/assets/{index-BGBqohfQ.js → index-BbKEXUFH.js} +5 -5
- package/lib/public/assets/{index-BTYMAqNW.css → index-Bxoxt9sV.css} +1 -1
- package/lib/public/assets/{index-BQ2luT7L.js → index-DJGc1M2f.js} +1 -1
- package/lib/public/assets/{input-BvB1cjHE.js → input-Cm0tmSoc.js} +1 -1
- package/lib/public/assets/{line-chart-m78VggnW.js → line-chart-D2DyJCml.js} +1 -1
- package/lib/public/assets/{list-checks-cY7o1QTL.js → list-checks-UWf1GY99.js} +1 -1
- package/lib/public/assets/{lock-loz8txQm.js → lock-CCJv9m_I.js} +1 -1
- package/lib/public/assets/{login-BYOvz4lx.js → login-f8vOVW-U.js} +1 -1
- package/lib/public/assets/maintenance-settings-C1PrkuAH.js +6 -0
- package/lib/public/assets/{monitor-C4HPHb6s.js → monitor-B2jDgwm7.js} +1 -1
- package/lib/public/assets/{mouse-pointer-2-BkdKtCzi.js → mouse-pointer-2-DLI1RtzU.js} +1 -1
- package/lib/public/assets/{network-C5e0MIWo.js → network-ebT86qoi.js} +1 -1
- package/lib/public/assets/{overview-tlu8ijGd.js → overview-C0aykVrd.js} +1 -1
- package/lib/public/assets/{page-header-FXPlo6az.js → page-header-BjzgWz-T.js} +1 -1
- package/lib/public/assets/{play-CWdk0_Sy.js → play-DLG9t8FU.js} +1 -1
- package/lib/public/assets/{plus-B2xCnntV.js → plus-nBFSMu_X.js} +1 -1
- package/lib/public/assets/{profile-page-D080qzr4.js → profile-page-CSl0UYlv.js} +1 -1
- package/lib/public/assets/{reset-password-D3u4Mbvn.js → reset-password-LeOuHqmB.js} +1 -1
- package/lib/public/assets/{runbook-page-hPRZMy7s.js → runbook-page-CMMeQml9.js} +1 -1
- package/lib/public/assets/{select-12RThAXc.js → select-88jHcl-Z.js} +1 -1
- package/lib/public/assets/{selector-detail-redirect-uQwvV7EQ.js → selector-detail-redirect-BbXKJjZM.js} +1 -1
- package/lib/public/assets/{selector-health-page-CThoxDFO.js → selector-health-page-B4rA1Xkv.js} +2 -2
- package/lib/public/assets/session-detail-page-COL_RZxw.js +4 -0
- package/lib/public/assets/settings-GF6ZMSQ6.js +6 -0
- package/lib/public/assets/{stat-tile-B02WEte8.js → stat-tile-BV98e_Sv.js} +1 -1
- package/lib/public/assets/{tablet-Dj30VGZl.js → tablet-BiAsnFDj.js} +1 -1
- package/lib/public/assets/{teams-uL4fjTDR.js → teams-B4-jrr-1.js} +1 -1
- package/lib/public/assets/{trash-2-B54e-TfY.js → trash-2-C5RSuX0e.js} +1 -1
- package/lib/public/assets/{upload-B3k8WCSP.js → upload-BG7_rMXK.js} +1 -1
- package/lib/public/assets/{use-builds-data-BFn90NH3.js → use-builds-data-J-riQYyC.js} +1 -1
- package/lib/public/assets/{use-password-reset-mode-DL2TmWZ0.js → use-password-reset-mode-C8-eH-UG.js} +1 -1
- package/lib/public/assets/{users-CqBuxMlX.js → users-CFba5TSy.js} +1 -1
- package/lib/public/assets/{users-DjQSucKb.js → users-Cp0beJm3.js} +1 -1
- package/lib/public/assets/{video-off-T0rlt0GA.js → video-off-DDsEISjV.js} +1 -1
- package/lib/public/assets/webhook-settings-BGu32vSB.js +1 -0
- package/lib/public/assets/{zap-gBHqutZV.js → zap-l4VaXzq8.js} +1 -1
- package/lib/public/index.html +2 -2
- package/lib/schema.json +19 -46
- package/lib/src/XenonCapabilityManager.js +22 -5
- package/lib/src/app/openapi/control.yaml +71 -20
- package/lib/src/app/openapi/grid.yaml +23 -5
- package/lib/src/app/openapi/platform.yaml +136 -28
- package/lib/src/app/routers/control.js +30 -5
- package/lib/src/app/routers/dashboard.js +29 -1
- package/lib/src/app/routers/grid.js +32 -10
- package/lib/src/app/routers/streamStartConflict.js +3 -0
- package/lib/src/app/routers/streamType.js +7 -2
- package/lib/src/app/routers/webhook.js +8 -4
- package/lib/src/config.js +50 -5
- package/lib/src/dashboard/commands.js +185 -141
- package/lib/src/dashboard/event-manager.js +39 -6
- 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 +46 -1
- package/lib/src/data-service/device-store.js +66 -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 +152 -9
- package/lib/src/data-service/web-config-service.js +43 -92
- package/lib/src/device-managers/AndroidDeviceManager.js +9 -31
- 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 +143 -37
- package/lib/src/generated/client/edge.js +17 -3
- package/lib/src/generated/client/index-browser.js +14 -0
- package/lib/src/generated/client/index.d.ts +2054 -379
- package/lib/src/generated/client/index.js +17 -3
- package/lib/src/generated/client/package.json +1 -1
- package/lib/src/generated/client/schema.prisma +35 -7
- package/lib/src/generated/client/wasm.js +14 -0
- package/lib/src/interceptors/CommandInterceptor.js +29 -8
- package/lib/src/interceptors/xenonScripts.js +55 -0
- package/lib/src/interfaces/IPluginArgs.js +1 -2
- package/lib/src/middleware/deviceAccessGuard.js +63 -9
- package/lib/src/plugin.js +15 -1
- package/lib/src/prisma.js +1 -1
- package/lib/src/scripts/database-check.js +124 -0
- package/lib/src/services/AIService.js +99 -0
- package/lib/src/services/CleanupService.js +6 -1
- 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 +5 -0
- package/lib/src/services/PortAllocator.js +5 -0
- package/lib/src/services/ServerManager.js +97 -8
- package/lib/src/services/SessionLifecycleService.js +63 -53
- package/lib/src/services/ShutdownCoordinator.js +33 -0
- package/lib/src/services/TeamService.js +20 -3
- package/lib/src/services/device-access/SessionOwnerResolver.js +26 -0
- package/lib/src/services/device-access/deviceAccessPolicy.js +38 -6
- package/lib/src/services/device-access/leaseHold.js +26 -0
- package/lib/src/services/device-access/ticketActorAccess.js +6 -0
- package/lib/src/services/healing/HealingOrchestrator.js +32 -1
- package/lib/src/services/interceptor/AndroidProxyAdapter.js +18 -0
- package/lib/src/services/interceptor/interceptorOptions.js +44 -0
- package/lib/src/services/lease/activeLeases.js +37 -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/omni-vision/OmniVisionService.js +53 -43
- 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/recording/busy-precheck.js +24 -3
- package/lib/src/services/recording/concurrency-gate.js +12 -3
- package/lib/src/services/settings/SelfHealingSwitch.js +70 -0
- package/lib/src/services/settings/labSettings.js +149 -0
- package/lib/src/services/webhookEvents.js +173 -0
- package/lib/test/helpers/fake-adb.js +58 -0
- package/lib/test/helpers/fake-device-table.js +63 -24
- package/lib/test/helpers/scratch-database.js +1 -0
- package/lib/test/unit/TeamService.test.js +3 -0
- package/lib/test/unit/XenonCapabilityManager.spec.js +4 -2
- package/lib/test/unit/apple-family.spec.js +36 -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-team-scope.spec.js +9 -6
- 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-access-lease.spec.js +270 -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/hub-node-gateway-appium-server.spec.js +48 -0
- package/lib/test/unit/hub-node-same-host.spec.js +5 -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/allocate-lease-branch.spec.js +22 -0
- package/lib/test/unit/lease/session-lease-proof.spec.js +59 -0
- package/lib/test/unit/lease-held-phone.spec.js +196 -0
- package/lib/test/unit/max-sessions.spec.js +240 -0
- package/lib/test/unit/ocr-text-match.spec.js +44 -0
- package/lib/test/unit/omni-vision-analyze-screen.spec.js +72 -0
- package/lib/test/unit/omni-vision-ios-points.spec.js +161 -0
- package/lib/test/unit/omni-vision-tap-text.spec.js +129 -0
- package/lib/test/unit/omni-vision.spec.js +1 -1
- package/lib/test/unit/partial-config-file.spec.js +114 -0
- 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/recording-options.spec.js +181 -0
- package/lib/test/unit/schema-required-args.spec.js +21 -16
- package/lib/test/unit/self-healing-boot.spec.js +75 -0
- package/lib/test/unit/self-healing-setting.spec.js +272 -0
- package/lib/test/unit/session-failed-webhook.spec.js +170 -0
- package/lib/test/unit/shell-commands.spec.js +133 -0
- package/lib/test/unit/socketServer.scopedEmit.spec.js +2 -0
- package/lib/test/unit/stream-start-pipelines.spec.js +210 -0
- package/lib/test/unit/stream-status-type.spec.js +4 -0
- package/lib/test/unit/vision-assertion.spec.js +118 -0
- package/lib/test/unit/wda-client-shell.spec.js +133 -0
- package/lib/test/unit/web-config-service.spec.js +79 -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 +1 -1
- package/prisma/migrations/20261004140000_keep_device_settings/migration.sql +19 -0
- package/prisma/schema.prisma +35 -7
- package/schema.json +19 -46
- package/scripts/generate-types-from-schema.js +7 -2
- package/scripts/lib/always-present-plugin-args.js +42 -0
- package/lib/public/assets/DeviceMosaicView-ChhHnpFQ.js +0 -2
- package/lib/public/assets/device-explorer-DSpAA_t9.js +0 -279
- package/lib/public/assets/maintenance-settings-BxbA7SkB.js +0 -6
- package/lib/public/assets/recording-group-store-B75435xR.js +0 -26
- package/lib/public/assets/session-detail-page-Bc02YjMm.js +0 -4
- package/lib/public/assets/settings-C1VIluuT.js +0 -6
- package/lib/public/assets/webhook-settings-DAHgnJyZ.js +0 -1
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
require("reflect-metadata");
|
|
49
|
+
const chai_1 = require("chai");
|
|
50
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
51
|
+
const typedi_1 = require("typedi");
|
|
52
|
+
const assetManager = __importStar(require("../../src/dashboard/asset-manager"));
|
|
53
|
+
const commands_1 = require("../../src/dashboard/commands");
|
|
54
|
+
const SessionManager_1 = require("../../src/sessions/SessionManager");
|
|
55
|
+
const SocketServer_1 = require("../../src/services/SocketServer");
|
|
56
|
+
const container_registration_1 = require("../helpers/container-registration");
|
|
57
|
+
const scratch_database_1 = require("../helpers/scratch-database");
|
|
58
|
+
/**
|
|
59
|
+
* The five execute commands that write to a session's record:
|
|
60
|
+
* setSessionName, setSessionStatus, debug, addTag and captureEvidence.
|
|
61
|
+
*
|
|
62
|
+
* A session has a record (a Session row) only on a hub with its dashboard
|
|
63
|
+
* on. Elsewhere (the dashboard off, or on a node, which never keeps one for
|
|
64
|
+
* the hub's sessions) setSessionName and setSessionStatus threw Prisma's
|
|
65
|
+
* P2025 and debug a foreign-key error, failing the test's command, while
|
|
66
|
+
* addTag and captureEvidence answered as if they had worked.
|
|
67
|
+
*
|
|
68
|
+
* Each now answers `{ recorded: true }` when it wrote, or `{ recorded: false,
|
|
69
|
+
* message }` saying why nothing was written. None of them fails the test's
|
|
70
|
+
* command: they are bookkeeping, and a test shouldn't die because its server
|
|
71
|
+
* keeps no dashboard.
|
|
72
|
+
*/
|
|
73
|
+
describe('xenon: session-details commands', () => {
|
|
74
|
+
const scratch = (0, scratch_database_1.useScratchDatabase)();
|
|
75
|
+
const SESSION = 'session-details-1';
|
|
76
|
+
let restoreContainer;
|
|
77
|
+
let emitted;
|
|
78
|
+
beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
79
|
+
yield scratch.db.log.deleteMany({});
|
|
80
|
+
yield scratch.db.sessionLog.deleteMany({});
|
|
81
|
+
yield scratch.db.session.deleteMany({});
|
|
82
|
+
restoreContainer = (0, container_registration_1.saveRegistrations)(SocketServer_1.SocketServer);
|
|
83
|
+
const socket = new SocketServer_1.SocketServer();
|
|
84
|
+
typedi_1.Container.set(SocketServer_1.SocketServer, socket);
|
|
85
|
+
emitted = sinon_1.default.stub(socket, 'emitToDashboardForDevices').resolves();
|
|
86
|
+
}));
|
|
87
|
+
afterEach(() => {
|
|
88
|
+
SessionManager_1.SESSION_MANAGER.removeSession(SESSION);
|
|
89
|
+
sinon_1.default.restore();
|
|
90
|
+
restoreContainer();
|
|
91
|
+
});
|
|
92
|
+
function withRecord() {
|
|
93
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
94
|
+
yield scratch.db.session.create({
|
|
95
|
+
data: {
|
|
96
|
+
id: SESSION,
|
|
97
|
+
desired_capabilities: '{}',
|
|
98
|
+
session_capabilities: '{}',
|
|
99
|
+
node_id: 'node-1',
|
|
100
|
+
has_live_video: false,
|
|
101
|
+
device_udid: 'phone-1',
|
|
102
|
+
device_platform: 'android',
|
|
103
|
+
device_version: '14',
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/** What the command answers, as the local interceptor and the hub's gateway both see it. */
|
|
109
|
+
function run(script, args) {
|
|
110
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
let body;
|
|
112
|
+
const response = {
|
|
113
|
+
status: (code) => ({
|
|
114
|
+
json: (d) => {
|
|
115
|
+
body = Object.assign({ code }, d);
|
|
116
|
+
return d;
|
|
117
|
+
},
|
|
118
|
+
}),
|
|
119
|
+
};
|
|
120
|
+
yield commands_1.dashboardCommands.process(SESSION, { body: { script, args } }, response);
|
|
121
|
+
return body;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
describe('which scripts are session-details commands', () => {
|
|
125
|
+
it('knows the five, under either prefix, and nothing else', () => {
|
|
126
|
+
(0, chai_1.expect)((0, commands_1.sessionDetailsCommandOf)('xenon: setSessionName')).to.equal('setSessionName');
|
|
127
|
+
(0, chai_1.expect)((0, commands_1.sessionDetailsCommandOf)('xe:addTag')).to.equal('addTag');
|
|
128
|
+
(0, chai_1.expect)((0, commands_1.sessionDetailsCommandOf)(' xenon : captureEvidence ')).to.equal('captureEvidence');
|
|
129
|
+
for (const other of [
|
|
130
|
+
'xenon: smartTap',
|
|
131
|
+
'xe: setAutowaitProperties',
|
|
132
|
+
'xenon: addMock',
|
|
133
|
+
'xenon: unknownThing',
|
|
134
|
+
'mobile: shell',
|
|
135
|
+
'xenonsetSessionName',
|
|
136
|
+
'return 1',
|
|
137
|
+
undefined,
|
|
138
|
+
42,
|
|
139
|
+
]) {
|
|
140
|
+
(0, chai_1.expect)((0, commands_1.sessionDetailsCommandOf)(other), String(other)).to.equal(null);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
describe('with no session record', () => {
|
|
145
|
+
const cases = [
|
|
146
|
+
['xenon: setSessionName', ['Checkout']],
|
|
147
|
+
['xenon: setSessionStatus', [{ status: 'passed' }]],
|
|
148
|
+
['xenon: debug', ['reached checkout']],
|
|
149
|
+
['xenon: addTag', ['smoke']],
|
|
150
|
+
['xenon: captureEvidence', ['Payment confirmed']],
|
|
151
|
+
];
|
|
152
|
+
for (const [script, args] of cases) {
|
|
153
|
+
it(`${script} answers that nothing was recorded, and writes nothing`, () => __awaiter(void 0, void 0, void 0, function* () {
|
|
154
|
+
const body = yield run(script, args);
|
|
155
|
+
(0, chai_1.expect)(body.code).to.equal(200);
|
|
156
|
+
(0, chai_1.expect)(body.value).to.include({ recorded: false });
|
|
157
|
+
(0, chai_1.expect)(body.value.message).to.match(/no record/i);
|
|
158
|
+
(0, chai_1.expect)(yield scratch.db.log.count()).to.equal(0);
|
|
159
|
+
(0, chai_1.expect)(yield scratch.db.sessionLog.count()).to.equal(0);
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
describe('with a session record', () => {
|
|
164
|
+
beforeEach(withRecord);
|
|
165
|
+
it('setSessionName names the session', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
166
|
+
var _a, _b;
|
|
167
|
+
(0, chai_1.expect)((yield run('xenon: setSessionName', ['Checkout'])).value).to.deep.equal({
|
|
168
|
+
recorded: true,
|
|
169
|
+
});
|
|
170
|
+
(0, chai_1.expect)((_a = (yield scratch.db.session.findUnique({ where: { id: SESSION } }))) === null || _a === void 0 ? void 0 : _a.name).to.equal('Checkout');
|
|
171
|
+
yield run('xe: setSessionName', [{ name: 'Checkout by card' }]);
|
|
172
|
+
(0, chai_1.expect)((_b = (yield scratch.db.session.findUnique({ where: { id: SESSION } }))) === null || _b === void 0 ? void 0 : _b.name).to.equal('Checkout by card');
|
|
173
|
+
}));
|
|
174
|
+
it('setSessionName without a name records nothing, and says so', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
175
|
+
const body = yield run('xenon: setSessionName', []);
|
|
176
|
+
(0, chai_1.expect)(body.value).to.include({ recorded: false });
|
|
177
|
+
(0, chai_1.expect)(body.value.message).to.match(/name/);
|
|
178
|
+
}));
|
|
179
|
+
it('setSessionStatus sets the status and reason, and tells the dashboard', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
180
|
+
var _a;
|
|
181
|
+
const body = yield run('xenon: setSessionStatus', [{ status: 'failed', reason: 'No total' }]);
|
|
182
|
+
(0, chai_1.expect)(body.value).to.deep.equal({ recorded: true });
|
|
183
|
+
const row = yield scratch.db.session.findUnique({ where: { id: SESSION } });
|
|
184
|
+
(0, chai_1.expect)(row).to.include({ status: 'failed', failure_reason: 'No total' });
|
|
185
|
+
(0, chai_1.expect)(emitted.firstCall.args[1]).to.include({
|
|
186
|
+
id: SESSION,
|
|
187
|
+
status: 'failed',
|
|
188
|
+
failure_reason: 'No total',
|
|
189
|
+
});
|
|
190
|
+
yield run('xenon: setSessionStatus', ['passed']);
|
|
191
|
+
(0, chai_1.expect)((_a = (yield scratch.db.session.findUnique({ where: { id: SESSION } }))) === null || _a === void 0 ? void 0 : _a.status).to.equal('success');
|
|
192
|
+
}));
|
|
193
|
+
it('setSessionStatus with a status it does not know records nothing, and says so', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
194
|
+
var _a;
|
|
195
|
+
const body = yield run('xenon: setSessionStatus', [{ status: 'skipped' }]);
|
|
196
|
+
(0, chai_1.expect)(body.value).to.include({ recorded: false });
|
|
197
|
+
(0, chai_1.expect)(body.value.message).to.match(/skipped/);
|
|
198
|
+
(0, chai_1.expect)((_a = (yield scratch.db.session.findUnique({ where: { id: SESSION } }))) === null || _a === void 0 ? void 0 : _a.status).to.equal('running');
|
|
199
|
+
}));
|
|
200
|
+
it('debug adds a debug line', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
201
|
+
(0, chai_1.expect)((yield run('xenon: debug', ['reached checkout'])).value).to.deep.equal({
|
|
202
|
+
recorded: true,
|
|
203
|
+
});
|
|
204
|
+
yield run('xenon: debug', [{ message: 'paid' }]);
|
|
205
|
+
const lines = yield scratch.db.log.findMany({ orderBy: { createdAt: 'asc' } });
|
|
206
|
+
(0, chai_1.expect)(lines.map((l) => [l.log_type, l.message])).to.deep.equal([
|
|
207
|
+
['DEBUG', 'reached checkout'],
|
|
208
|
+
['DEBUG', 'paid'],
|
|
209
|
+
]);
|
|
210
|
+
}));
|
|
211
|
+
it('debug without a message records nothing, and says so', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
212
|
+
const body = yield run('xenon: debug', []);
|
|
213
|
+
(0, chai_1.expect)(body.value).to.include({ recorded: false });
|
|
214
|
+
(0, chai_1.expect)(yield scratch.db.log.count()).to.equal(0);
|
|
215
|
+
}));
|
|
216
|
+
it('addTag adds a tag once', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
217
|
+
(0, chai_1.expect)((yield run('xenon: addTag', ['smoke'])).value).to.deep.equal({ recorded: true });
|
|
218
|
+
(0, chai_1.expect)((yield run('xenon: addTag', [{ tag: 'smoke' }])).value).to.deep.equal({
|
|
219
|
+
recorded: true,
|
|
220
|
+
});
|
|
221
|
+
yield run('xenon: addTag', ['regression']);
|
|
222
|
+
const row = yield scratch.db.session.findUnique({ where: { id: SESSION } });
|
|
223
|
+
(0, chai_1.expect)(JSON.parse(String(row === null || row === void 0 ? void 0 : row.tags))).to.deep.equal(['smoke', 'regression']);
|
|
224
|
+
}));
|
|
225
|
+
it('captureEvidence records a screenshot of a session this server drives', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
226
|
+
SessionManager_1.SESSION_MANAGER.addSession(SESSION, { getScreenShot: () => __awaiter(void 0, void 0, void 0, function* () { return 'aGVsbG8='; }) });
|
|
227
|
+
sinon_1.default.stub(assetManager, 'saveScreenShot').returns(`${SESSION}/screenshots/x.png`);
|
|
228
|
+
const body = yield run('xenon: captureEvidence', [{ reason: 'Paid', label: 'receipt' }]);
|
|
229
|
+
(0, chai_1.expect)(body.value).to.deep.equal({ recorded: true });
|
|
230
|
+
const rows = yield scratch.db.sessionLog.findMany({});
|
|
231
|
+
(0, chai_1.expect)(rows.map((r) => [r.command_name, r.subtitle, r.screenshot])).to.deep.equal([
|
|
232
|
+
['captureEvidence', 'Paid', `${SESSION}/screenshots/x.png`],
|
|
233
|
+
]);
|
|
234
|
+
}));
|
|
235
|
+
it("captureEvidence records nothing, and says so, when it can't take a screenshot", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
236
|
+
let body = yield run('xenon: captureEvidence', ['Paid']);
|
|
237
|
+
(0, chai_1.expect)(body.value).to.include({ recorded: false });
|
|
238
|
+
SessionManager_1.SESSION_MANAGER.addSession(SESSION, {
|
|
239
|
+
getScreenShot: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
240
|
+
throw new Error('WDA is not running');
|
|
241
|
+
}),
|
|
242
|
+
});
|
|
243
|
+
body = yield run('xenon: captureEvidence', ['Paid']);
|
|
244
|
+
(0, chai_1.expect)(body.value).to.include({ recorded: false });
|
|
245
|
+
(0, chai_1.expect)(body.value.message).to.match(/WDA is not running/);
|
|
246
|
+
(0, chai_1.expect)(yield scratch.db.sessionLog.count()).to.equal(0);
|
|
247
|
+
}));
|
|
248
|
+
});
|
|
249
|
+
});
|
|
@@ -253,6 +253,8 @@ describe('Dashboard events name their phone (team-scoped call sites)', () => {
|
|
|
253
253
|
delete teams[filter.udid];
|
|
254
254
|
})),
|
|
255
255
|
updateDevice: sinon_1.default.stub().resolves(),
|
|
256
|
+
// removeDevice reads the row for the device_offline webhook's name and platform.
|
|
257
|
+
findDevice: sinon_1.default.stub().resolves(null),
|
|
256
258
|
getDevices: sinon_1.default.stub().resolves([
|
|
257
259
|
{
|
|
258
260
|
udid: 'phone-b',
|
|
@@ -308,13 +310,14 @@ describe('Dashboard events name their phone (team-scoped call sites)', () => {
|
|
|
308
310
|
}));
|
|
309
311
|
});
|
|
310
312
|
it("xenon: setSessionStatus: the updated session's device", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
313
|
+
sinon_1.default.stub(prisma_1.prisma.session, 'findUnique').resolves({ id: 's3', tags: null });
|
|
311
314
|
sinon_1.default.stub(prisma_1.prisma.session, 'update').resolves({ id: 's3', device_udid: 'phone-b' });
|
|
312
315
|
const res = { status: () => res, json: () => res };
|
|
313
316
|
yield new commands_1.DashboardCommands().process('s3', {
|
|
314
317
|
body: { script: 'xenon: setSessionStatus', args: [{ status: 'failed', reason: 'boom' }] },
|
|
315
318
|
}, res);
|
|
316
319
|
const [call] = scoped(SocketEvents_1.SocketEvents.SESSION_STOPPED);
|
|
317
|
-
(0, chai_1.expect)(call.args[1]).to.deep.equal({ id: 's3', status: 'failed', failure_reason:
|
|
320
|
+
(0, chai_1.expect)(call.args[1]).to.deep.equal({ id: 's3', status: 'failed', failure_reason: 'boom' });
|
|
318
321
|
(0, chai_1.expect)(call.args[2]).to.deep.equal({ udid: 'phone-b' });
|
|
319
322
|
}));
|
|
320
323
|
describe('interceptor', () => {
|
|
@@ -400,11 +403,10 @@ describe('Dashboard events name their phone (team-scoped call sites)', () => {
|
|
|
400
403
|
}));
|
|
401
404
|
it('a team change (PUT /device/:udid/team) refreshes the resolver at once', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
402
405
|
sinon_1.default.stub(prisma_1.prisma.team, 'findUnique').resolves({ id: 'team-c' });
|
|
403
|
-
|
|
404
|
-
sinon_1.default
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
sinon_1.default.stub(device_store_1.DeviceStoreFactory.getStore(), 'updateDevice').resolves();
|
|
406
|
+
const store = device_store_1.DeviceStoreFactory.getStore();
|
|
407
|
+
sinon_1.default.stub(store, 'findDevices').resolves([{ udid: 'phone-a', host: 'h' }]);
|
|
408
|
+
sinon_1.default.stub(store, 'findSavedPhones').resolves([]);
|
|
409
|
+
const write = sinon_1.default.stub(store, 'updateDevice').resolves();
|
|
408
410
|
const resolver = typedi_1.Container.get(DeviceTeamResolver_1.DeviceTeamResolver);
|
|
409
411
|
yield resolver.resolve('phone-a'); // cached as team-a
|
|
410
412
|
const app = (0, express_1.default)();
|
|
@@ -424,6 +426,7 @@ describe('Dashboard events name their phone (team-scoped call sites)', () => {
|
|
|
424
426
|
app.use(router);
|
|
425
427
|
const res = yield (0, loopbackRequest_1.default)(app).put('/device/phone-a/team').send({ teamId: 'team-c' });
|
|
426
428
|
(0, chai_1.expect)(res.status).to.equal(200);
|
|
429
|
+
(0, chai_1.expect)(write.firstCall.args).to.deep.equal(['phone-a', 'h', { teamId: 'team-c' }]);
|
|
427
430
|
(0, chai_1.expect)(yield resolver.resolve('phone-a')).to.deep.equal({ known: true, teamId: 'team-c' });
|
|
428
431
|
(0, chai_1.expect)(lookups).to.deep.equal(['phone-a']);
|
|
429
432
|
}));
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const chai_1 = require("chai");
|
|
7
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
8
|
+
const config_1 = require("../../src/config");
|
|
9
|
+
const logger_1 = __importDefault(require("../../src/logger"));
|
|
10
|
+
const database_check_1 = require("../../src/scripts/database-check");
|
|
11
|
+
// The published plugin ships a database client generated for SQLite. Through
|
|
12
|
+
// 2.13.1, `databaseProvider: postgresql` with a SQLite file URL quietly ran on
|
|
13
|
+
// SQLite (Xenon Control profiles did exactly this), and a postgres URL stopped
|
|
14
|
+
// the server with Prisma's "the URL must start with the protocol `file:`" under
|
|
15
|
+
// a hint about adding a column to a table with rows.
|
|
16
|
+
describe('checkDatabase', () => {
|
|
17
|
+
const sqliteFile = 'file:/Users/me/.cache/xenon/xenon.db';
|
|
18
|
+
const postgresUrl = 'postgresql://xenon:s3cret@db.example.com:5432/xenon';
|
|
19
|
+
it('accepts a SQLite file with a SQLite client and says nothing', () => {
|
|
20
|
+
(0, chai_1.expect)((0, database_check_1.checkDatabase)({ configured: 'sqlite', url: sqliteFile, client: 'sqlite' })).to.deep.equal({});
|
|
21
|
+
});
|
|
22
|
+
it('runs a SQLite file on a SQLite client when configured for postgresql, with a warning', () => {
|
|
23
|
+
const { warning } = (0, database_check_1.checkDatabase)({
|
|
24
|
+
configured: 'postgresql',
|
|
25
|
+
url: sqliteFile,
|
|
26
|
+
client: 'sqlite',
|
|
27
|
+
});
|
|
28
|
+
(0, chai_1.expect)(warning).to.be.a('string');
|
|
29
|
+
(0, chai_1.expect)(warning).to.match(/databaseProvider/);
|
|
30
|
+
(0, chai_1.expect)(warning).to.match(/SQLite/);
|
|
31
|
+
(0, chai_1.expect)(warning).to.include('/Users/me/.cache/xenon/xenon.db');
|
|
32
|
+
});
|
|
33
|
+
it('refuses a postgres URL when the client is built for SQLite, without printing the password', () => {
|
|
34
|
+
(0, chai_1.expect)(() => (0, database_check_1.checkDatabase)({ configured: 'postgresql', url: postgresUrl, client: 'sqlite' }))
|
|
35
|
+
.to.throw(/SQLite/)
|
|
36
|
+
.with.property('message')
|
|
37
|
+
.that.does.not.include('s3cret');
|
|
38
|
+
});
|
|
39
|
+
it('refuses a postgres URL even when databaseProvider says sqlite', () => {
|
|
40
|
+
(0, chai_1.expect)(() => (0, database_check_1.checkDatabase)({ configured: 'sqlite', url: postgresUrl, client: 'sqlite' })).to.throw(/db\.example\.com/);
|
|
41
|
+
});
|
|
42
|
+
it('accepts a postgres URL when the client was generated for PostgreSQL', () => {
|
|
43
|
+
(0, chai_1.expect)((0, database_check_1.checkDatabase)({ configured: 'postgresql', url: postgresUrl, client: 'postgresql' })).to.deep.equal({});
|
|
44
|
+
});
|
|
45
|
+
it('refuses a SQLite file when the client was generated for PostgreSQL', () => {
|
|
46
|
+
(0, chai_1.expect)(() => (0, database_check_1.checkDatabase)({ configured: 'postgresql', url: sqliteFile, client: 'postgresql' })).to.throw(/PostgreSQL/);
|
|
47
|
+
});
|
|
48
|
+
it('refuses a URL it cannot place', () => {
|
|
49
|
+
(0, chai_1.expect)(() => (0, database_check_1.checkDatabase)({ configured: 'sqlite', url: 'mysql://h/db', client: 'sqlite' })).to.throw(/mysql:/);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('clientProviderFromSchema', () => {
|
|
53
|
+
it("reads the datasource's provider, not the generator's", () => {
|
|
54
|
+
const schema = [
|
|
55
|
+
'generator client {',
|
|
56
|
+
' provider = "prisma-client-js"',
|
|
57
|
+
'}',
|
|
58
|
+
'',
|
|
59
|
+
'datasource db {',
|
|
60
|
+
' provider = "postgresql"',
|
|
61
|
+
' url = env("DATABASE_URL")',
|
|
62
|
+
'}',
|
|
63
|
+
].join('\n');
|
|
64
|
+
(0, chai_1.expect)((0, database_check_1.clientProviderFromSchema)(schema)).to.equal('postgresql');
|
|
65
|
+
});
|
|
66
|
+
it('returns null when there is no datasource', () => {
|
|
67
|
+
(0, chai_1.expect)((0, database_check_1.clientProviderFromSchema)('generator client {}')).to.equal(null);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('describeDatabaseUrl', () => {
|
|
71
|
+
it('keeps a SQLite path and drops credentials from a server URL', () => {
|
|
72
|
+
(0, chai_1.expect)((0, database_check_1.describeDatabaseUrl)('file:/data/xenon.db')).to.equal('/data/xenon.db');
|
|
73
|
+
(0, chai_1.expect)((0, database_check_1.describeDatabaseUrl)('postgresql://u:p@h:5432/db?schema=x')).to.equal('postgresql://h:5432/db');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('assertSupportedDatabase', () => {
|
|
77
|
+
let saved;
|
|
78
|
+
beforeEach(() => {
|
|
79
|
+
saved = { provider: config_1.config.databaseProvider, url: config_1.config.databaseUrl };
|
|
80
|
+
});
|
|
81
|
+
afterEach(() => {
|
|
82
|
+
config_1.config.databaseProvider = saved.provider;
|
|
83
|
+
config_1.config.databaseUrl = saved.url;
|
|
84
|
+
sinon_1.default.restore();
|
|
85
|
+
});
|
|
86
|
+
// These read the generated client this repo ships (src/generated/client),
|
|
87
|
+
// which is built for SQLite.
|
|
88
|
+
it('stops a server whose URL is a postgres database', () => {
|
|
89
|
+
config_1.config.databaseProvider = 'postgresql';
|
|
90
|
+
config_1.config.databaseUrl = 'postgresql://xenon:pw@127.0.0.1:5432/xenon';
|
|
91
|
+
(0, chai_1.expect)(() => (0, database_check_1.assertSupportedDatabase)()).to.throw(/built for SQLite/);
|
|
92
|
+
});
|
|
93
|
+
it('starts a postgresql-labelled server on its SQLite file, and says so once', () => {
|
|
94
|
+
const warn = sinon_1.default.stub(logger_1.default, 'warn');
|
|
95
|
+
config_1.config.databaseProvider = 'postgresql';
|
|
96
|
+
config_1.config.databaseUrl = 'file:/tmp/xenon-check.db';
|
|
97
|
+
(0, database_check_1.assertSupportedDatabase)();
|
|
98
|
+
(0, chai_1.expect)(warn.callCount).to.equal(1);
|
|
99
|
+
(0, chai_1.expect)(String(warn.firstCall.args[0])).to.include('/tmp/xenon-check.db');
|
|
100
|
+
});
|
|
101
|
+
it('is silent for the default SQLite setup', () => {
|
|
102
|
+
const warn = sinon_1.default.stub(logger_1.default, 'warn');
|
|
103
|
+
config_1.config.databaseProvider = 'sqlite';
|
|
104
|
+
config_1.config.databaseUrl = 'file:/tmp/xenon-check.db';
|
|
105
|
+
(0, database_check_1.assertSupportedDatabase)();
|
|
106
|
+
(0, chai_1.expect)(warn.called).to.equal(false);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const chai_1 = require("chai");
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const IPluginArgs_1 = require("../../src/interfaces/IPluginArgs");
|
|
10
|
+
const schema = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '..', '..', 'schema.json'), 'utf8'));
|
|
11
|
+
/**
|
|
12
|
+
* Appium fills every default schema.json declares, so a server started the
|
|
13
|
+
* normal way runs on those. DefaultPluginArgs (the block in
|
|
14
|
+
* scripts/generate-types-from-schema.js) is the copy the plugin merges under
|
|
15
|
+
* its options, and used to say 86400000 ms for the health check while the
|
|
16
|
+
* schema, and so the running server, said 300000. A second copy that can
|
|
17
|
+
* disagree is how the Settings page came to show a third number.
|
|
18
|
+
*/
|
|
19
|
+
describe('DefaultPluginArgs', () => {
|
|
20
|
+
it('agrees with every default schema.json declares', () => {
|
|
21
|
+
const disagreements = Object.entries(schema.properties)
|
|
22
|
+
.filter(([key, prop]) => 'default' in prop && key in IPluginArgs_1.DefaultPluginArgs)
|
|
23
|
+
.filter(([key, prop]) => IPluginArgs_1.DefaultPluginArgs[key] !== undefined &&
|
|
24
|
+
JSON.stringify(IPluginArgs_1.DefaultPluginArgs[key]) !==
|
|
25
|
+
JSON.stringify(prop.default))
|
|
26
|
+
.map(([key, prop]) => ({
|
|
27
|
+
key,
|
|
28
|
+
schema: prop.default,
|
|
29
|
+
defaultPluginArgs: IPluginArgs_1.DefaultPluginArgs[key],
|
|
30
|
+
}));
|
|
31
|
+
(0, chai_1.expect)(disagreements).to.deep.equal([]);
|
|
32
|
+
});
|
|
33
|
+
});
|