@xenon-device-management/xenon 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/README.md +446 -0
  2. package/lib/package.json +207 -0
  3. package/lib/public/assets/Layouts-7IT8aFLI.js +11 -0
  4. package/lib/public/assets/Layouts-DPMls9vh.css +1 -0
  5. package/lib/public/assets/ai-settings-BbnfgdEx.js +11 -0
  6. package/lib/public/assets/apps-CRMrI4_p.js +16 -0
  7. package/lib/public/assets/apps-CcM77dgg.css +1 -0
  8. package/lib/public/assets/badge-B1nKs8zj.css +1 -0
  9. package/lib/public/assets/badge-CSvl5xIU.js +11 -0
  10. package/lib/public/assets/button-CJlKn4PZ.css +1 -0
  11. package/lib/public/assets/button-CvLaGFYj.js +26 -0
  12. package/lib/public/assets/calendar-6w-D6Oaw.js +6 -0
  13. package/lib/public/assets/clock-DcdeWBPr.js +6 -0
  14. package/lib/public/assets/cpu-DiSoXT9n.js +6 -0
  15. package/lib/public/assets/device-explorer-CajM63OJ.js +193 -0
  16. package/lib/public/assets/device-explorer-CxdUAoTL.css +1 -0
  17. package/lib/public/assets/index-ByQwMN5T.js +174 -0
  18. package/lib/public/assets/index-C1DBaoSh.js +1 -0
  19. package/lib/public/assets/index-qzCez_kk.css +1 -0
  20. package/lib/public/assets/lock-B23ibZmo.js +6 -0
  21. package/lib/public/assets/maintenance-settings-CirzA6yG.js +6 -0
  22. package/lib/public/assets/mouse-pointer-2-Cz76SHFb.js +6 -0
  23. package/lib/public/assets/plus-BBwlIevt.js +6 -0
  24. package/lib/public/assets/session-dashboard-C2k7FFv_.css +1 -0
  25. package/lib/public/assets/session-dashboard-HPDtwPOZ.js +62 -0
  26. package/lib/public/assets/settings-DrZsZwdc.js +1 -0
  27. package/lib/public/assets/trash-2-DQpvzJec.js +6 -0
  28. package/lib/public/assets/useSocket-Dxsqae2a.js +16 -0
  29. package/lib/public/assets/webhook-settings-CDPgsgkb.css +1 -0
  30. package/lib/public/assets/webhook-settings-Cp-B4Nrw.js +1 -0
  31. package/lib/public/assets/zap-DovP6iow.js +6 -0
  32. package/lib/public/favicon.ico +0 -0
  33. package/lib/public/favicon.png +0 -0
  34. package/lib/public/favicon.svg +9 -0
  35. package/lib/public/index.html +46 -0
  36. package/lib/public/logo.svg +17 -0
  37. package/lib/public/logo192.png +0 -0
  38. package/lib/public/logo512.png +0 -0
  39. package/lib/public/manifest.json +25 -0
  40. package/lib/public/robots.txt +3 -0
  41. package/lib/schema.json +348 -0
  42. package/lib/src/InternalHttpClient.js +212 -0
  43. package/lib/src/PluginContext.js +29 -0
  44. package/lib/src/XenonCapabilityManager.js +199 -0
  45. package/lib/src/app/index.js +167 -0
  46. package/lib/src/app/routers/apps.js +79 -0
  47. package/lib/src/app/routers/config.js +131 -0
  48. package/lib/src/app/routers/control.js +835 -0
  49. package/lib/src/app/routers/dashboard.js +301 -0
  50. package/lib/src/app/routers/grid.js +352 -0
  51. package/lib/src/app/routers/reservation.js +190 -0
  52. package/lib/src/app/routers/webhook.js +83 -0
  53. package/lib/src/app/swagger-docs.js +203 -0
  54. package/lib/src/app/swagger.js +366 -0
  55. package/lib/src/chromeUtils.js +148 -0
  56. package/lib/src/commands/handle.js +19 -0
  57. package/lib/src/commands/index.js +8 -0
  58. package/lib/src/config.js +73 -0
  59. package/lib/src/dashboard/asset-manager.js +84 -0
  60. package/lib/src/dashboard/commands.js +284 -0
  61. package/lib/src/dashboard/event-manager.js +699 -0
  62. package/lib/src/dashboard/services/app-service.js +134 -0
  63. package/lib/src/dashboard/services/failure-analysis-service.js +173 -0
  64. package/lib/src/dashboard/services/session-service.js +113 -0
  65. package/lib/src/data-service/CircuitBreaker.js +83 -0
  66. package/lib/src/data-service/config-service.js +155 -0
  67. package/lib/src/data-service/db.js +122 -0
  68. package/lib/src/data-service/device-service.js +320 -0
  69. package/lib/src/data-service/device-store.interface.js +2 -0
  70. package/lib/src/data-service/device-store.js +345 -0
  71. package/lib/src/data-service/pending-sessions-service.js +25 -0
  72. package/lib/src/data-service/pluginArgs.js +25 -0
  73. package/lib/src/data-service/prisma-service.js +31 -0
  74. package/lib/src/data-service/prisma-store.js +385 -0
  75. package/lib/src/data-service/queue-service.js +150 -0
  76. package/lib/src/data-service/web-config-service.js +130 -0
  77. package/lib/src/device-managers/AndroidDeviceManager.js +1155 -0
  78. package/lib/src/device-managers/ChromeDriverManager.js +68 -0
  79. package/lib/src/device-managers/HealthMonitorService.js +325 -0
  80. package/lib/src/device-managers/IOSDeviceManager.js +351 -0
  81. package/lib/src/device-managers/NodeDevices.js +82 -0
  82. package/lib/src/device-managers/android/AndroidStreamService.js +370 -0
  83. package/lib/src/device-managers/android/DeviceLockManager.js +45 -0
  84. package/lib/src/device-managers/cloud/CapabilityManager.js +26 -0
  85. package/lib/src/device-managers/cloud/Devices.js +86 -0
  86. package/lib/src/device-managers/iOSTracker.js +44 -0
  87. package/lib/src/device-managers/index.js +89 -0
  88. package/lib/src/device-managers/ios/IOSDiscoveryService.js +268 -0
  89. package/lib/src/device-managers/ios/IOSStreamService.js +893 -0
  90. package/lib/src/device-managers/ios/WDAClient.js +866 -0
  91. package/lib/src/device-utils.js +663 -0
  92. package/lib/src/enums/Capabilities.js +8 -0
  93. package/lib/src/enums/Cloud.js +11 -0
  94. package/lib/src/enums/Platform.js +9 -0
  95. package/lib/src/enums/SessionType.js +9 -0
  96. package/lib/src/enums/SocketEvents.js +15 -0
  97. package/lib/src/helpers/UniversalMjpegProxy.js +273 -0
  98. package/lib/src/helpers/index.js +229 -0
  99. package/lib/src/index.js +95 -0
  100. package/lib/src/interceptors/CommandInterceptor.js +524 -0
  101. package/lib/src/interfaces/ICloudManager.js +2 -0
  102. package/lib/src/interfaces/IDevice.js +2 -0
  103. package/lib/src/interfaces/IDeviceFilterOptions.js +2 -0
  104. package/lib/src/interfaces/IDeviceManager.js +2 -0
  105. package/lib/src/interfaces/IOptions.js +2 -0
  106. package/lib/src/interfaces/IPluginArgs.js +55 -0
  107. package/lib/src/interfaces/ISessionCapability.js +2 -0
  108. package/lib/src/logger.js +225 -0
  109. package/lib/src/plugin.js +244 -0
  110. package/lib/src/prisma.js +12 -0
  111. package/lib/src/profiling/AndroidAppProfiler.js +213 -0
  112. package/lib/src/proxy/wd-command-proxy.js +221 -0
  113. package/lib/src/scripts/generate-database-migration.js +59 -0
  114. package/lib/src/scripts/initialize-database.js +55 -0
  115. package/lib/src/scripts/install-go-ios.js +66 -0
  116. package/lib/src/scripts/prepare-prisma.js +89 -0
  117. package/lib/src/services/AICommandService.js +143 -0
  118. package/lib/src/services/AIService.js +466 -0
  119. package/lib/src/services/CleanupService.js +141 -0
  120. package/lib/src/services/EventBus.js +74 -0
  121. package/lib/src/services/InspectorService.js +395 -0
  122. package/lib/src/services/MetricsService.js +134 -0
  123. package/lib/src/services/NetworkConditioningService.js +173 -0
  124. package/lib/src/services/NotificationService.js +163 -0
  125. package/lib/src/services/RequestLogService.js +252 -0
  126. package/lib/src/services/ResourceIsolationService.js +122 -0
  127. package/lib/src/services/SecurityService.js +120 -0
  128. package/lib/src/services/ServerManager.js +284 -0
  129. package/lib/src/services/SessionHeartbeatService.js +158 -0
  130. package/lib/src/services/SessionLifecycleService.js +572 -0
  131. package/lib/src/services/SocketClient.js +71 -0
  132. package/lib/src/services/SocketServer.js +87 -0
  133. package/lib/src/services/TracingService.js +132 -0
  134. package/lib/src/services/VideoPipelineService.js +220 -0
  135. package/lib/src/services/healing/FuzzyXmlHealingProvider.js +333 -0
  136. package/lib/src/services/healing/HealEtalonService.js +98 -0
  137. package/lib/src/services/healing/HealedLocatorGenerator.js +132 -0
  138. package/lib/src/services/healing/HealingOrchestrator.js +165 -0
  139. package/lib/src/services/healing/LlmHealingProvider.js +77 -0
  140. package/lib/src/services/healing/OcrHealingProvider.js +119 -0
  141. package/lib/src/services/healing/ResilioTreeHealingProvider.js +100 -0
  142. package/lib/src/services/healing/VisualAiHealingProvider.js +90 -0
  143. package/lib/src/services/healing/types.js +12 -0
  144. package/lib/src/services/omni-vision/OmniVisionService.js +718 -0
  145. package/lib/src/services/omni-vision/VisionAssertionService.js +68 -0
  146. package/lib/src/sessions/CloudSession.js +42 -0
  147. package/lib/src/sessions/LocalSession.js +313 -0
  148. package/lib/src/sessions/RemoteSession.js +287 -0
  149. package/lib/src/sessions/SessionManager.js +238 -0
  150. package/lib/src/sessions/XenonSession.js +44 -0
  151. package/lib/src/types/CLIArgs.js +2 -0
  152. package/lib/src/types/CloudArgs.js +2 -0
  153. package/lib/src/types/CloudSchema.js +131 -0
  154. package/lib/src/types/DeviceType.js +2 -0
  155. package/lib/src/types/DeviceUpdate.js +2 -0
  156. package/lib/src/types/IOSDevice.js +2 -0
  157. package/lib/src/types/Platform.js +2 -0
  158. package/lib/src/types/SessionStatus.js +11 -0
  159. package/lib/src/validators/CapabilityValidator.js +93 -0
  160. package/lib/test/e2e/android/conf.spec.js +43 -0
  161. package/lib/test/e2e/android/conf2.spec.js +44 -0
  162. package/lib/test/e2e/android/conf3.spec.js +44 -0
  163. package/lib/test/e2e/e2ehelper.js +113 -0
  164. package/lib/test/e2e/hubnode/forward-request.spec.js +224 -0
  165. package/lib/test/e2e/hubnode/hubnode.spec.js +214 -0
  166. package/lib/test/e2e/ios/conf1.spec.js +39 -0
  167. package/lib/test/e2e/ios/conf2.spec.js +39 -0
  168. package/lib/test/e2e/plugin-harness.js +236 -0
  169. package/lib/test/e2e/plugin.spec.js +97 -0
  170. package/lib/test/e2e/telemetry_verification.spec.js +83 -0
  171. package/lib/test/e2e/video-recording-test.spec.js +63 -0
  172. package/lib/test/helpers/test-container.js +112 -0
  173. package/lib/test/integration/androidDevices.spec.js +137 -0
  174. package/lib/test/integration/cliArgs.js +73 -0
  175. package/lib/test/integration/ios/01iOSSimulator.spec.js +291 -0
  176. package/lib/test/integration/ios/02iOSDevices.spec.js +75 -0
  177. package/lib/test/integration/testHelpers.js +74 -0
  178. package/lib/test/unit/AndroidDeviceManager.spec.js +178 -0
  179. package/lib/test/unit/ChromeDriverManager.spec.js +26 -0
  180. package/lib/test/unit/CleanupService.spec.js +21 -0
  181. package/lib/test/unit/DeviceModel.spec.js +157 -0
  182. package/lib/test/unit/FuzzyXmlHealingProvider.test.js +294 -0
  183. package/lib/test/unit/GetAdbOriginal.js +42 -0
  184. package/lib/test/unit/HealingCascade.test.js +128 -0
  185. package/lib/test/unit/IOSDeviceManager.spec.js +261 -0
  186. package/lib/test/unit/RemoteIOs.spec.js +78 -0
  187. package/lib/test/unit/ResilioTreeHealingProvider.test.js +96 -0
  188. package/lib/test/unit/commands.spec.js +27 -0
  189. package/lib/test/unit/config.spec.js +27 -0
  190. package/lib/test/unit/device-service.spec.js +307 -0
  191. package/lib/test/unit/device-utils.spec.js +313 -0
  192. package/lib/test/unit/fixtures/device.config.js +4 -0
  193. package/lib/test/unit/fixtures/devices.js +89 -0
  194. package/lib/test/unit/helpers.spec.js +62 -0
  195. package/lib/test/unit/omni-vision.spec.js +100 -0
  196. package/lib/test/unit/plugin.spec.js +133 -0
  197. package/lib/tsconfig.tsbuildinfo +1 -0
  198. package/package.json +207 -0
  199. package/prisma/data.db +0 -0
  200. package/prisma/dev.db +0 -0
  201. package/prisma/dev.db-journal +0 -0
  202. package/prisma/migrations/20231011074725_initial_tables/migration.sql +47 -0
  203. package/prisma/migrations/20231226115334_update_session_log/migration.sql +2 -0
  204. package/prisma/migrations/20251204113710_add_video_recording_enabled/migration.sql +29 -0
  205. package/prisma/migrations/20251204132449_add_log_table/migration.sql +11 -0
  206. package/prisma/migrations/20251205050111_add_profiling_support/migration.sql +47 -0
  207. package/prisma/migrations/20251205050947_add_is_error_field/migration.sql +24 -0
  208. package/prisma/migrations/20260126201337_add_app_model/migration.sql +18 -0
  209. package/prisma/migrations/20260130115722_add_performance_trace_and_xenon_sync/migration.sql +2 -0
  210. package/prisma/migrations/20260130135114_add_device_models/migration.sql +57 -0
  211. package/prisma/migrations/20260130140655_make_systemport_optional/migration.sql +45 -0
  212. package/prisma/migrations/20260130140932_make_device_fields_optional/migration.sql +45 -0
  213. package/prisma/migrations/20260130141040_final_schema_fix/migration.sql +45 -0
  214. package/prisma/migrations/20260130143234_add_device_health_fields/migration.sql +4 -0
  215. package/prisma/migrations/20260130144921_add_failure_category/migration.sql +2 -0
  216. package/prisma/migrations/20260131151456_add_webhook_config/migration.sql +10 -0
  217. package/prisma/migrations/20260201094507_add_device_tags/migration.sql +11 -0
  218. package/prisma/migrations/20260201103410_add_managed_process/migration.sql +15 -0
  219. package/prisma/migrations/20260201140637_add_web_config/migration.sql +22 -0
  220. package/prisma/migrations/20260201162232_add_session_progress/migration.sql +2 -0
  221. package/prisma/migrations/20260201174231_add_total_healed_count/migration.sql +2 -0
  222. package/prisma/migrations/migration_lock.toml +3 -0
  223. package/prisma/schema.prisma +210 -0
  224. package/schema.json +348 -0
  225. package/scripts/build-xenon.sh +32 -0
  226. package/scripts/dev/debug-gemini.ts +44 -0
  227. package/scripts/generate-types-from-schema.js +86 -0
  228. package/scripts/install-compatible-driver.js +39 -0
@@ -0,0 +1,261 @@
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 sinon_1 = __importDefault(require("sinon"));
50
+ const chai_1 = require("chai");
51
+ const IOSDeviceManager_1 = __importDefault(require("../../src/device-managers/IOSDeviceManager"));
52
+ const IOSDiscoveryService_1 = require("../../src/device-managers/ios/IOSDiscoveryService");
53
+ const Helper = __importStar(require("../../src/helpers"));
54
+ const DeviceUtils = __importStar(require("../../src/device-utils"));
55
+ const devices_1 = require("./fixtures/devices");
56
+ const ip_1 = __importDefault(require("ip"));
57
+ const IPluginArgs_1 = require("../../src/interfaces/IPluginArgs");
58
+ let sandbox = sinon_1.default.createSandbox();
59
+ beforeEach(() => {
60
+ if (IOSDiscoveryService_1.IOSDiscoveryService.prototype.getDevices.restore) {
61
+ IOSDiscoveryService_1.IOSDiscoveryService.prototype.getDevices.restore();
62
+ }
63
+ sinon_1.default.restore();
64
+ sandbox = sinon_1.default.createSandbox();
65
+ });
66
+ afterEach(function () {
67
+ sandbox.restore();
68
+ });
69
+ const pluginArgs = Object.assign({}, IPluginArgs_1.DefaultPluginArgs, {
70
+ remote: [`http://${ip_1.default.address()}:4723`],
71
+ skipChromeDownload: true,
72
+ });
73
+ describe('IOS Device Manager', () => {
74
+ it('IOS Device List to have added state', () => __awaiter(void 0, void 0, void 0, function* () {
75
+ const iosDevices = new IOSDeviceManager_1.default(pluginArgs, 4723);
76
+ sandbox.stub(IOSDiscoveryService_1.IOSDiscoveryService.prototype, 'getDevices').resolves([
77
+ {
78
+ udid: '00001111-00115D822222002E',
79
+ sdk: '14.1.1',
80
+ name: 'Sai’s iPhone',
81
+ busy: false,
82
+ realDevice: true,
83
+ deviceType: 'real',
84
+ platform: 'ios',
85
+ wdaLocalPort: 54093,
86
+ sessionStartTime: 0,
87
+ totalUtilizationTimeMilliSec: 0,
88
+ host: `http://${ip_1.default.address()}:4723`,
89
+ derivedDataPath: 'dummy',
90
+ mjpegServerPort: 54093,
91
+ },
92
+ {
93
+ name: 'iPad Air (3rd generation)',
94
+ udid: '0FBCBDCC-2FF1-4FCA-B034-60ABC86ED866',
95
+ state: 'Shutdown',
96
+ sdk: '13.5',
97
+ platform: 'ios',
98
+ deviceType: 'simulator',
99
+ host: `http://${ip_1.default.address()}:4723`,
100
+ },
101
+ {
102
+ name: 'iPad Air (3rd generation)',
103
+ udid: '0FBCBDCC-2FF1-4FCA-B034-60ABC86E9999',
104
+ state: 'Booted',
105
+ sdk: '14.5',
106
+ platform: 'ios',
107
+ deviceType: 'simulator',
108
+ host: `http://${ip_1.default.address()}:4723`,
109
+ },
110
+ ]);
111
+ sandbox.stub(Helper, 'isMac').returns(true);
112
+ const devices = yield iosDevices.getDevices({ iosDeviceType: 'both' }, []);
113
+ (0, chai_1.expect)(devices).to.have.lengthOf(3);
114
+ (0, chai_1.expect)(devices[0].udid).to.equal('00001111-00115D822222002E');
115
+ (0, chai_1.expect)(devices[1].udid).to.equal('0FBCBDCC-2FF1-4FCA-B034-60ABC86ED866');
116
+ (0, chai_1.expect)(devices[2].udid).to.equal('0FBCBDCC-2FF1-4FCA-B034-60ABC86E9999');
117
+ }));
118
+ it('Should consider only simulators that is given by user and all real devices', () => __awaiter(void 0, void 0, void 0, function* () {
119
+ const simulators = [
120
+ {
121
+ name: 'iPhone 14',
122
+ sdk: '16.1',
123
+ },
124
+ {
125
+ name: 'iPhone 14 Plus',
126
+ sdk: '16.1',
127
+ },
128
+ ];
129
+ let iosDeviceManager = new IOSDeviceManager_1.default(Object.assign({ platform: 'iOS', simulators }, IPluginArgs_1.DefaultPluginArgs), 4723);
130
+ const mockSims = devices_1.deviceMock.filter((device) => device.platform === 'ios' && device.deviceType === 'simulator');
131
+ sandbox.stub(IOSDiscoveryService_1.IOSDiscoveryService.prototype, 'getDevices').resolves([
132
+ {
133
+ udid: '00001111-00115D822222002E',
134
+ sdk: '14.1.1',
135
+ name: 'Sai’s iPhone',
136
+ busy: false,
137
+ realDevice: true,
138
+ deviceType: 'real',
139
+ platform: 'ios',
140
+ wdaLocalPort: 54093,
141
+ sessionStartTime: 0,
142
+ totalUtilizationTimeMilliSec: 0,
143
+ host: `http://${ip_1.default.address()}:4723`,
144
+ derivedDataPath: 'dummy',
145
+ mjpegServerPort: 54093,
146
+ },
147
+ ...mockSims
148
+ ]);
149
+ sandbox.stub(Helper, 'getFreePort').returns(54093);
150
+ sandbox.stub(DeviceUtils, 'getUtilizationTime').returns(0);
151
+ const devices = yield iosDeviceManager.getDevices({ iosDeviceType: 'real' }, []);
152
+ devices.forEach((device) => {
153
+ (0, chai_1.expect)(device.platform).to.equal('ios');
154
+ });
155
+ }));
156
+ it('Should consider only simulators that is given by user and not real devices', () => __awaiter(void 0, void 0, void 0, function* () {
157
+ const simulators = [
158
+ {
159
+ name: 'iPhone 14',
160
+ sdk: '16.1',
161
+ },
162
+ {
163
+ name: 'iPhone 14 Plus',
164
+ sdk: '16.1',
165
+ },
166
+ ];
167
+ let iosDeviceManager = new IOSDeviceManager_1.default(Object.assign({ platform: 'iOS', iosDeviceType: 'simulated', remote: ['http://127.0.0.1:4723'], simulators }, IPluginArgs_1.DefaultPluginArgs), 4723);
168
+ const mockSims = devices_1.deviceMock.filter((device) => device.platform === 'ios' && device.deviceType === 'simulator');
169
+ sandbox.stub(IOSDiscoveryService_1.IOSDiscoveryService.prototype, 'getDevices').resolves(mockSims);
170
+ sandbox.stub(Helper, 'getFreePort').returns(54093);
171
+ sandbox.stub(DeviceUtils, 'getUtilizationTime').returns(0);
172
+ const devices = yield iosDeviceManager.getDevices({ iosDeviceType: 'simulated' }, []);
173
+ devices.forEach((device) => {
174
+ (0, chai_1.expect)(device.realDevice).to.be.false;
175
+ });
176
+ }));
177
+ it('IOS Device List to have added state - Include simulators with real devices', () => __awaiter(void 0, void 0, void 0, function* () {
178
+ const iosDevices = new IOSDeviceManager_1.default(IPluginArgs_1.DefaultPluginArgs, 4723);
179
+ sandbox.stub(IOSDiscoveryService_1.IOSDiscoveryService.prototype, 'getDevices').resolves([
180
+ {
181
+ udid: '00001111-00115D822222002E',
182
+ sdk: '14.1.1',
183
+ name: 'Sai’s iPhone',
184
+ busy: false,
185
+ realDevice: true,
186
+ deviceType: 'real',
187
+ platform: 'ios',
188
+ wdaLocalPort: 54093,
189
+ host: `http://${ip_1.default.address()}:4723`,
190
+ derivedDataPath: 'dummy',
191
+ mjpegServerPort: 54093,
192
+ sessionStartTime: 0,
193
+ totalUtilizationTimeMilliSec: 0,
194
+ },
195
+ {
196
+ name: 'iPad Air (3rd generation)',
197
+ udid: '0FBCBDCC-2FF1-4FCA-B034-60ABC86ED866',
198
+ state: 'Shutdown',
199
+ sdk: '13.5',
200
+ platform: 'ios',
201
+ deviceType: 'simulator',
202
+ host: `http://${ip_1.default.address()}:4723`,
203
+ },
204
+ ]);
205
+ const devices = yield iosDevices.getDevices({ iosDeviceType: 'both' }, []);
206
+ (0, chai_1.expect)(devices).to.have.lengthOf(2);
207
+ (0, chai_1.expect)(devices[0].udid).to.equal('00001111-00115D822222002E');
208
+ (0, chai_1.expect)(devices[1].udid).to.equal('0FBCBDCC-2FF1-4FCA-B034-60ABC86ED866');
209
+ }));
210
+ it('IOS Device List to have added state - Only simulators', () => __awaiter(void 0, void 0, void 0, function* () {
211
+ const iosDevices = new IOSDeviceManager_1.default(IPluginArgs_1.DefaultPluginArgs, 4723);
212
+ sandbox.stub(IOSDiscoveryService_1.IOSDiscoveryService.prototype, 'getDevices').resolves([
213
+ {
214
+ name: 'iPad Air (3rd generation)',
215
+ udid: '0FBCBDCC-2FF1-4FCA-B034-60ABC86ED866',
216
+ state: 'Shutdown',
217
+ sdk: '13.5',
218
+ platform: 'ios',
219
+ deviceType: 'simulator',
220
+ host: `http://${ip_1.default.address()}:4723`,
221
+ },
222
+ ]);
223
+ sandbox.stub(Helper, 'getFreePort').returns(54093);
224
+ sandbox.stub(DeviceUtils, 'getUtilizationTime').returns(0);
225
+ const devices = yield iosDevices.getDevices({ iosDeviceType: 'simulated' }, []);
226
+ (0, chai_1.expect)(devices).to.deep.equal([
227
+ {
228
+ name: 'iPad Air (3rd generation)',
229
+ udid: '0FBCBDCC-2FF1-4FCA-B034-60ABC86ED866',
230
+ state: 'Shutdown',
231
+ sdk: '13.5',
232
+ platform: 'ios',
233
+ deviceType: 'simulator',
234
+ host: `http://${ip_1.default.address()}:4723`,
235
+ },
236
+ ]);
237
+ }));
238
+ it('IOS Device List to have added state - Only real devices', () => __awaiter(void 0, void 0, void 0, function* () {
239
+ const iosDevices = new IOSDeviceManager_1.default(IPluginArgs_1.DefaultPluginArgs, 4723);
240
+ sandbox.stub(IOSDiscoveryService_1.IOSDiscoveryService.prototype, 'getDevices').resolves([
241
+ {
242
+ udid: '00001111-00115D822222002E',
243
+ sdk: '14.1.1',
244
+ name: 'Sai’s iPhone',
245
+ busy: false,
246
+ realDevice: true,
247
+ deviceType: 'real',
248
+ platform: 'ios',
249
+ wdaLocalPort: 54093,
250
+ sessionStartTime: 0,
251
+ totalUtilizationTimeMilliSec: 0,
252
+ host: `http://${ip_1.default.address()}:4723`,
253
+ derivedDataPath: 'dummy',
254
+ mjpegServerPort: 54093,
255
+ }
256
+ ]);
257
+ const devices = yield iosDevices.getDevices({ iosDeviceType: 'real' }, []);
258
+ (0, chai_1.expect)(devices).to.have.lengthOf(1);
259
+ (0, chai_1.expect)(devices[0].udid).to.equal('00001111-00115D822222002E');
260
+ }));
261
+ });
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ require("reflect-metadata");
16
+ const sinon_1 = __importDefault(require("sinon"));
17
+ const axios_1 = __importDefault(require("axios"));
18
+ const chai_1 = require("chai");
19
+ const IOSDeviceManager_1 = __importDefault(require("../../src/device-managers/IOSDeviceManager"));
20
+ const IOSDiscoveryService_1 = require("../../src/device-managers/ios/IOSDiscoveryService");
21
+ let sandbox = sinon_1.default.createSandbox();
22
+ beforeEach(function () {
23
+ if (IOSDiscoveryService_1.IOSDiscoveryService.prototype.getDevices.restore) {
24
+ IOSDiscoveryService_1.IOSDiscoveryService.prototype.getDevices.restore();
25
+ }
26
+ sinon_1.default.restore();
27
+ sandbox = sinon_1.default.createSandbox();
28
+ });
29
+ afterEach(function () {
30
+ sinon_1.default.restore();
31
+ sandbox.restore();
32
+ });
33
+ const stubResponse = {
34
+ data: [
35
+ {
36
+ name: 'iPad (8th generation)',
37
+ udid: '3F74FBC0-D50E-4317-8C33-428C1CE55C27',
38
+ state: 'Shutdown',
39
+ sdk: '14.2',
40
+ platform: 'ios',
41
+ busy: false,
42
+ realDevice: false,
43
+ deviceType: 'simulator',
44
+ },
45
+ ],
46
+ status: 200,
47
+ statusText: 'OK',
48
+ headers: {},
49
+ config: {},
50
+ };
51
+ describe('Remote IOS', () => __awaiter(void 0, void 0, void 0, function* () {
52
+ it('Fetch remote devices', function () {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ let stub = sinon_1.default.stub(axios_1.default, 'post').resolves(stubResponse);
55
+ const iosDevices = new IOSDeviceManager_1.default({});
56
+ sandbox.stub(IOSDiscoveryService_1.IOSDiscoveryService.prototype, 'getDevices').resolves([
57
+ {
58
+ wdaLocalPort: 54093,
59
+ udid: '00001111-00115D822222002E',
60
+ sdk: '14.1.1',
61
+ name: 'Sai’s iPhone',
62
+ busy: false,
63
+ realDevice: true,
64
+ deviceType: 'real',
65
+ platform: 'ios',
66
+ host: 'http://127.0.0.1:4723',
67
+ derivedDataPath: 'dummy',
68
+ mjpegServerPort: 54093,
69
+ sessionStartTime: 0,
70
+ totalUtilizationTimeMilliSec: 0,
71
+ }
72
+ ]);
73
+ const devices = yield iosDevices.getDevices({ iosDeviceType: 'both' }, []);
74
+ (0, chai_1.expect)(devices).to.have.lengthOf(1);
75
+ (0, chai_1.expect)(devices[0].udid).to.equal('00001111-00115D822222002E');
76
+ });
77
+ });
78
+ }));
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const chai_1 = require("chai");
13
+ const types_1 = require("../../src/services/healing/types");
14
+ const ResilioTreeHealingProvider_1 = require("../../src/services/healing/ResilioTreeHealingProvider");
15
+ const { JSDOMParser, Path } = require('resiliotree');
16
+ describe('ResilioTreeHealingProvider', () => {
17
+ let provider;
18
+ let mockEtalonService;
19
+ const sourceXml = `
20
+ <hierarchy>
21
+ <android.widget.FrameLayout index="0">
22
+ <android.widget.LinearLayout index="0">
23
+ <android.widget.Button index="0" text="Submit" resource-id="com.example:id/submit_btn" />
24
+ <android.widget.TextView index="1" text="Hello" />
25
+ </android.widget.LinearLayout>
26
+ </android.widget.FrameLayout>
27
+ </hierarchy>
28
+ `;
29
+ const brokenXml = `
30
+ <hierarchy>
31
+ <android.widget.FrameLayout index="0">
32
+ <android.widget.LinearLayout index="0">
33
+ <android.widget.Button index="0" text="Send" resource-id="com.example:id/send_btn" />
34
+ <android.widget.TextView index="1" text="Hello World" />
35
+ </android.widget.LinearLayout>
36
+ </android.widget.FrameLayout>
37
+ </hierarchy>
38
+ `;
39
+ beforeEach(() => {
40
+ mockEtalonService = {
41
+ getSignature: () => __awaiter(void 0, void 0, void 0, function* () { return null; }),
42
+ };
43
+ provider = new ResilioTreeHealingProvider_1.ResilioTreeHealingProvider(mockEtalonService);
44
+ });
45
+ it('should heal an element when a ResilioTree path exists', () => __awaiter(void 0, void 0, void 0, function* () {
46
+ const parser = new JSDOMParser();
47
+ const root = parser.parse(sourceXml);
48
+ // Find the button in source
49
+ const bodyNode = root.children[0];
50
+ const hierarchyNode = bodyNode.children[0];
51
+ const frameLayout = hierarchyNode.children[0];
52
+ const linearLayout = frameLayout.children[0];
53
+ const buttonNode = linearLayout.children[0];
54
+ const path = new Path([root, bodyNode, hierarchyNode, frameLayout, linearLayout, buttonNode]);
55
+ mockEtalonService.getSignature = () => __awaiter(void 0, void 0, void 0, function* () {
56
+ return ({
57
+ selector: "//android.widget.Button[@text='Submit']",
58
+ strategy: 'xpath',
59
+ attributes: { text: 'Submit', 'resource-id': 'com.example:id/submit_btn' },
60
+ nodeName: 'android.widget.Button',
61
+ path: path.toJSON(),
62
+ lastSeen: Date.now(),
63
+ });
64
+ });
65
+ const mockDriver = {
66
+ findElement: (strategy, selector) => __awaiter(void 0, void 0, void 0, function* () {
67
+ (0, chai_1.expect)(strategy).to.equal('xpath');
68
+ (0, chai_1.expect)(selector.toLowerCase()).to.contain('android.widget.button');
69
+ return { ELEMENT: 'healed-element-123' };
70
+ }),
71
+ };
72
+ const context = {
73
+ sessionId: 'test-session',
74
+ driver: mockDriver,
75
+ strategy: 'xpath',
76
+ selector: "//android.widget.Button[@text='Submit']",
77
+ pageSource: brokenXml,
78
+ };
79
+ const result = yield provider.heal(context);
80
+ (0, chai_1.expect)(result).to.not.be.null;
81
+ (0, chai_1.expect)(result === null || result === void 0 ? void 0 : result.id).to.equal('healed-element-123');
82
+ (0, chai_1.expect)(result === null || result === void 0 ? void 0 : result.tier).to.equal(types_1.HealingTier.TIER_1_RECOVERY);
83
+ (0, chai_1.expect)(result === null || result === void 0 ? void 0 : result.message).to.contain('ResilioTree');
84
+ }));
85
+ it('should return null if no signature/path is found', () => __awaiter(void 0, void 0, void 0, function* () {
86
+ const context = {
87
+ sessionId: 'test-session',
88
+ driver: {},
89
+ strategy: 'xpath',
90
+ selector: '//unknown',
91
+ pageSource: brokenXml,
92
+ };
93
+ const result = yield provider.heal(context);
94
+ (0, chai_1.expect)(result).to.be.null;
95
+ }));
96
+ });
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const commands_1 = __importDefault(require("../../src/commands"));
16
+ const plugin_1 = require("../../src/plugin");
17
+ const chai_1 = require("chai");
18
+ describe('Plugin commands', () => {
19
+ it('Should handle empty or populated commands list', () => {
20
+ (0, chai_1.expect)(Object.keys(commands_1.default).length).to.be.at.least(0);
21
+ });
22
+ it('Should register commands to plugin', () => __awaiter(void 0, void 0, void 0, function* () {
23
+ for (var [name, command] of Object.entries(commands_1.default)) {
24
+ (0, chai_1.expect)(plugin_1.XenonPlugin.prototype[name]).to.equal(command);
25
+ }
26
+ }));
27
+ });
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const path_1 = __importDefault(require("path"));
16
+ const device_utils_1 = require("../../src/device-utils");
17
+ const chai_1 = require("chai");
18
+ describe('Config Test', () => {
19
+ it('Should be able to load data from absolute path from config', () => __awaiter(void 0, void 0, void 0, function* () {
20
+ const deviceConfigPath = path_1.default.resolve(__dirname, './fixtures/device.config.js');
21
+ (0, chai_1.expect)((0, device_utils_1.isDeviceConfigPathAbsolute)(deviceConfigPath)).to.be.true;
22
+ }));
23
+ it('Should throw error when path is not absolute', () => __awaiter(void 0, void 0, void 0, function* () {
24
+ const deviceConfigPath = './fixtures/device.config.js';
25
+ (0, chai_1.expect)(() => (0, device_utils_1.isDeviceConfigPathAbsolute)(deviceConfigPath)).to.throw('Device Config Path ./fixtures/device.config.js should be absolute');
26
+ }));
27
+ });