@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,178 @@
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 adbkit_1 = __importDefault(require("@devicefarmer/adbkit"));
18
+ const appium_adb_1 = require("appium-adb");
19
+ const chai_1 = require("chai");
20
+ const test_container_1 = require("../helpers/test-container");
21
+ const GetAdbOriginal_1 = require("./GetAdbOriginal");
22
+ const sandbox = sinon_1.default.createSandbox();
23
+ describe('Android Device Manager', () => {
24
+ let adb;
25
+ beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
26
+ sandbox.restore();
27
+ adb = yield (0, GetAdbOriginal_1.getAdbOriginal)();
28
+ // Neutralize real ADB discovery
29
+ sandbox.stub(appium_adb_1.ADB, 'createADB').returns(Promise.resolve(adb));
30
+ sandbox.stub(adbkit_1.default, 'createClient').returns({
31
+ trackDevices: () => {
32
+ const tracker = {
33
+ on: sandbox.stub(),
34
+ };
35
+ return tracker;
36
+ },
37
+ });
38
+ }));
39
+ afterEach(function () {
40
+ sandbox.restore();
41
+ });
42
+ it('Android Device List to have added state', () => __awaiter(void 0, void 0, void 0, function* () {
43
+ const androidDevices = (0, test_container_1.createTestAndroidManager)({ platform: 'android' });
44
+ // @ts-expect-error - Accessing private member for testing
45
+ androidDevices.adbAvailable = true;
46
+ sandbox.stub(androidDevices, 'getConnectedDevices').returns(Promise.resolve(new Map([
47
+ [
48
+ adb,
49
+ [
50
+ { udid: 'emulator-5554', state: 'device' },
51
+ { udid: 'emulator-5555', state: 'device' },
52
+ ],
53
+ ],
54
+ ])));
55
+ sandbox.stub(androidDevices, 'getDeviceVersion').returns(Promise.resolve('9'));
56
+ sandbox.stub(androidDevices, 'getDeviceName').returns(Promise.resolve('sdk_phone_x86'));
57
+ sandbox.stub(androidDevices, 'isRealDevice').returns(Promise.resolve(false));
58
+ const devices = yield androidDevices.getDevices({ androidDeviceType: 'both' }, []);
59
+ (0, chai_1.expect)(devices.length).to.be.equal(2);
60
+ (0, chai_1.expect)(devices[0]).to.have.property('state', 'device');
61
+ (0, chai_1.expect)(devices[1]).to.have.property('state', 'device');
62
+ }));
63
+ it('Android Device List to have added state - Only emulators', () => __awaiter(void 0, void 0, void 0, function* () {
64
+ const androidDevices = (0, test_container_1.createTestAndroidManager)({
65
+ platform: 'android',
66
+ androidDeviceType: 'simulated',
67
+ });
68
+ // @ts-expect-error - Accessing private member for testing
69
+ androidDevices.adbAvailable = true;
70
+ sandbox.stub(androidDevices, 'getConnectedDevices').returns(Promise.resolve(new Map([
71
+ [
72
+ adb,
73
+ [
74
+ { udid: 'emulator-5554', state: 'device' },
75
+ { udid: 'emulator-5555', state: 'device' },
76
+ ],
77
+ ],
78
+ ])));
79
+ sandbox.stub(androidDevices, 'getDeviceVersion').returns(Promise.resolve('9'));
80
+ sandbox.stub(androidDevices, 'getDeviceName').returns(Promise.resolve('sdk_phone_x86'));
81
+ sandbox.stub(androidDevices, 'isRealDevice').returns(Promise.resolve(false));
82
+ const devices = yield androidDevices.getDevices({ androidDeviceType: 'simulated' }, []);
83
+ (0, chai_1.expect)(devices.length).to.be.equal(2);
84
+ (0, chai_1.expect)(devices[0]).to.have.property('state', 'device');
85
+ (0, chai_1.expect)(devices[1]).to.have.property('state', 'device');
86
+ }));
87
+ it('Android Device List to have added state - Only real devices', () => __awaiter(void 0, void 0, void 0, function* () {
88
+ const androidDevices = (0, test_container_1.createTestAndroidManager)({
89
+ platform: 'android',
90
+ androidDeviceType: 'real',
91
+ });
92
+ // @ts-expect-error - Accessing private member for testing
93
+ androidDevices.adbAvailable = true;
94
+ sandbox.stub(androidDevices, 'getConnectedDevices').returns(Promise.resolve(new Map([
95
+ [
96
+ adb,
97
+ [
98
+ { udid: 'emulator-5554', state: 'device' },
99
+ { udid: 'YOGAA1BBB4124', state: 'device' },
100
+ ],
101
+ ],
102
+ ])));
103
+ sandbox.stub(androidDevices, 'getDeviceVersion').returns(Promise.resolve('9'));
104
+ sandbox.stub(androidDevices, 'getDeviceName').returns(Promise.resolve('sdk_phone_x86'));
105
+ sandbox.stub(androidDevices, 'isRealDevice').callsFake((...args) => __awaiter(void 0, void 0, void 0, function* () {
106
+ const udid = args[1];
107
+ return udid === 'YOGAA1BBB4124';
108
+ }));
109
+ const devices = yield androidDevices.getDevices({ androidDeviceType: 'real' }, []);
110
+ (0, chai_1.expect)(devices.length).to.be.equal(1);
111
+ (0, chai_1.expect)(devices[0]).to.have.property('udid', 'YOGAA1BBB4124');
112
+ }));
113
+ it('Android Device List to have host as remoteMachineProxyIP if provided', () => __awaiter(void 0, void 0, void 0, function* () {
114
+ const androidDevices = (0, test_container_1.createTestAndroidManager)({
115
+ platform: 'android',
116
+ remoteMachineProxyIP: '192.168.0.104',
117
+ });
118
+ // @ts-expect-error - Accessing private member for testing
119
+ androidDevices.adbAvailable = true;
120
+ sandbox.stub(androidDevices, 'getConnectedDevices').returns(Promise.resolve(new Map([
121
+ [
122
+ adb,
123
+ [
124
+ { udid: 'emulator-5554', state: 'device' },
125
+ { udid: 'YOGAA1BBB4124', state: 'device' },
126
+ ],
127
+ ],
128
+ ])));
129
+ sandbox.stub(androidDevices, 'getDeviceVersion').returns(Promise.resolve('9'));
130
+ sandbox.stub(androidDevices, 'getDeviceName').returns(Promise.resolve('sdk_phone_x86'));
131
+ sandbox.stub(androidDevices, 'isRealDevice').returns(Promise.resolve(true));
132
+ const devices = yield androidDevices.getDevices({ androidDeviceType: 'both' }, []);
133
+ (0, chai_1.expect)(devices.length).to.be.equal(2);
134
+ (0, chai_1.expect)(devices[0]).to.have.property('host', 'http://192.168.0.104:4723');
135
+ (0, chai_1.expect)(devices[1]).to.have.property('host', 'http://192.168.0.104:4723');
136
+ }));
137
+ it("Should handle error when adb doesn't respond", () => __awaiter(void 0, void 0, void 0, function* () {
138
+ const androidDevices = (0, test_container_1.createTestAndroidManager)({ platform: 'android' });
139
+ // @ts-expect-error - Accessing private member for testing
140
+ androidDevices.adbAvailable = true;
141
+ sandbox.stub(androidDevices, 'getConnectedDevices').returns(Promise.resolve(new Map([
142
+ [
143
+ adb,
144
+ [
145
+ { udid: 'emulator-9999', state: 'device' },
146
+ { udid: 'emulator-7777', state: 'device' },
147
+ ],
148
+ ],
149
+ ])));
150
+ sandbox.stub(androidDevices, 'deviceInfo').callsFake((device) => __awaiter(void 0, void 0, void 0, function* () {
151
+ if (device.udid === 'emulator-9999') {
152
+ throw new Error('Adb timeout');
153
+ }
154
+ return { udid: device.udid, state: device.state, host: 'Local' };
155
+ }));
156
+ const devices = yield androidDevices.getDevices({ androidDeviceType: 'both' }, []);
157
+ // check that emulator-7777 is returned and emulator-9999 is not
158
+ (0, chai_1.expect)(devices.length).to.be.equal(1);
159
+ (0, chai_1.expect)(devices[0]).to.have.property('udid', 'emulator-7777');
160
+ }));
161
+ it('should handle device never completing boot', () => __awaiter(void 0, void 0, void 0, function* () {
162
+ const androidDevices = (0, test_container_1.createTestAndroidManager)({ platform: 'android' });
163
+ // @ts-expect-error - Accessing private member for testing
164
+ androidDevices.adbAvailable = true;
165
+ sandbox.stub(androidDevices, 'getAdb').returns(Promise.resolve({ adbInstance: adb }));
166
+ sandbox
167
+ .stub(adb, 'shell')
168
+ .withArgs(['getprop', 'sys.boot_completed'])
169
+ .throwsException(new Error('Adb timeout'));
170
+ (0, chai_1.expect)(() => {
171
+ androidDevices.onDeviceAdded(adb, {
172
+ udid: 'emulator-9999',
173
+ state: 'device',
174
+ host: 'Local',
175
+ });
176
+ }).to.not.throw();
177
+ }));
178
+ });
@@ -0,0 +1,26 @@
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 ChromeDriverManager_1 = __importDefault(require("../../src/device-managers/ChromeDriverManager"));
16
+ const support_1 = require("@appium/support");
17
+ const chromeUtils_1 = require("../../src/chromeUtils");
18
+ describe('Chrome Driver Manager', function () {
19
+ this.timeout(500000);
20
+ it.skip('Should fetch chrome driver for given version', () => __awaiter(this, void 0, void 0, function* () {
21
+ const chromeDriverManager = yield ChromeDriverManager_1.default.getInstance();
22
+ yield chromeDriverManager.downloadChromeDriver(83);
23
+ yield chromeDriverManager.downloadChromeDriver(84);
24
+ (yield support_1.fs.readdir(yield (0, chromeUtils_1.getChromedriverBinaryPath)((0, chromeUtils_1.getModuleRoot)()))).length.should.be.eql(3);
25
+ }));
26
+ });
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const chai_1 = require("chai");
4
+ const CleanupService_1 = require("../../src/services/CleanupService");
5
+ const typedi_1 = require("typedi");
6
+ require("reflect-metadata");
7
+ describe('CleanupService Unit Tests', () => {
8
+ let cleanupService;
9
+ beforeEach(() => {
10
+ cleanupService = typedi_1.Container.get(CleanupService_1.CleanupService);
11
+ });
12
+ it('should be instantiable via TypeDI', () => {
13
+ (0, chai_1.expect)(cleanupService).to.be.an.instanceOf(CleanupService_1.CleanupService);
14
+ });
15
+ it('should have runCleanup method', () => {
16
+ (0, chai_1.expect)(cleanupService.runCleanup).to.be.a('function');
17
+ });
18
+ it('should have purgeBuild method', () => {
19
+ (0, chai_1.expect)(cleanupService.purgeBuild).to.be.a('function');
20
+ });
21
+ });
@@ -0,0 +1,157 @@
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 db_1 = require("../../src/data-service/db");
16
+ const device_service_1 = require("../../src/data-service/device-service");
17
+ const devices_1 = require("./fixtures/devices");
18
+ const chai_1 = require("chai");
19
+ const device_service_2 = require("../../src/data-service/device-service");
20
+ const sinon_1 = __importDefault(require("sinon"));
21
+ const sandbox = sinon_1.default.createSandbox();
22
+ const test_container_1 = require("../helpers/test-container");
23
+ describe('Model Test', () => __awaiter(void 0, void 0, void 0, function* () {
24
+ before('Add device collection', () => __awaiter(void 0, void 0, void 0, function* () {
25
+ yield (0, test_container_1.resetTestContainer)();
26
+ (0, chai_1.expect)((yield db_1.XenonDatabase.DeviceModel).chain().find().data().length).to.be.equal(0);
27
+ (0, chai_1.expect)(devices_1.deviceMock.length).to.be.greaterThanOrEqual(1);
28
+ // console.log(`deviceMock length: ${deviceMock.length}`);
29
+ (yield db_1.XenonDatabase.DeviceModel).insert(devices_1.deviceMock);
30
+ (yield db_1.XenonDatabase.db).saveDatabase();
31
+ // console.log(`result: ${result}`);
32
+ // console.log(`device model length: ${deviceModel.find().length}`);
33
+ (yield db_1.XenonDatabase.DeviceModel)
34
+ .chain()
35
+ .find()
36
+ .data()
37
+ .length.should.be.equal(devices_1.deviceMock.length);
38
+ }));
39
+ after('clean', () => {
40
+ sandbox.restore();
41
+ });
42
+ it('Should remove device from old pool when new poll call does not have the device', () => __awaiter(void 0, void 0, void 0, function* () {
43
+ const findDevice = (yield db_1.XenonDatabase.DeviceModel)
44
+ .chain()
45
+ .find({ udid: 'emulator-5570' })
46
+ .data();
47
+ (0, chai_1.expect)(findDevice.length).to.be.equal(1);
48
+ yield (0, device_service_2.removeDevice)([{ udid: 'emulator-5570', host: '127.0.0.1' }]);
49
+ const updatedDeviceList = (yield db_1.XenonDatabase.DeviceModel)
50
+ .chain()
51
+ .find({ udid: 'emulator-5570' })
52
+ .data();
53
+ (0, chai_1.expect)(updatedDeviceList).to.deep.equal([]);
54
+ }));
55
+ it('Should update new device polled into the existing device list', () => __awaiter(void 0, void 0, void 0, function* () {
56
+ const newDeviceList = [
57
+ {
58
+ busy: false,
59
+ state: 'device',
60
+ udid: 'emulator-9994',
61
+ platform: 'android',
62
+ host: '127.0.0.1',
63
+ },
64
+ ];
65
+ yield (0, device_service_2.addNewDevice)(newDeviceList);
66
+ const updatedDeviceList = (yield db_1.XenonDatabase.DeviceModel)
67
+ .chain()
68
+ .find({ udid: 'emulator-9994' })
69
+ .data();
70
+ (0, chai_1.expect)(updatedDeviceList.length).to.be.greaterThanOrEqual(1);
71
+ }));
72
+ it('Should update the ios simulator state from shutdown to booted', () => __awaiter(void 0, void 0, void 0, function* () {
73
+ const newDeviceList = [
74
+ {
75
+ busy: false,
76
+ state: 'device',
77
+ udid: 'emulator-5554',
78
+ platform: 'android',
79
+ offline: false,
80
+ host: '127.0.0.1',
81
+ },
82
+ {
83
+ busy: false,
84
+ state: 'device',
85
+ udid: 'emulator-5556',
86
+ platform: 'android',
87
+ offline: false,
88
+ host: '127.0.0.1',
89
+ },
90
+ {
91
+ name: 'iPad Air',
92
+ udid: '0FBCBDCC-2FF1-4FCA-B034-60ABC86ED888',
93
+ state: 'Shutdown',
94
+ deviceType: 'simulator',
95
+ sdk: '13.5',
96
+ platform: 'ios',
97
+ busy: true,
98
+ realDevice: false,
99
+ offline: false,
100
+ host: '127.0.0.1',
101
+ },
102
+ {
103
+ name: 'iPad Air (3rd generation)',
104
+ udid: '0FBCBDCC-2FF1-4FCA-B034-60ABC86ED866',
105
+ state: 'Shutdown',
106
+ deviceType: 'simulator',
107
+ sdk: '13.5',
108
+ platform: 'ios',
109
+ busy: false,
110
+ realDevice: false,
111
+ offline: false,
112
+ host: '127.0.0.1',
113
+ },
114
+ ];
115
+ yield (0, device_service_2.setSimulatorState)(newDeviceList);
116
+ const updatedDeviceList = (yield db_1.XenonDatabase.DeviceModel)
117
+ .chain()
118
+ .find({ udid: '0FBCBDCC-2FF1-4FCA-B034-60ABC86ED888' })
119
+ .data();
120
+ (0, chai_1.expect)(updatedDeviceList[0].state).to.be.equal('Shutdown');
121
+ }));
122
+ it('Should handle concurrent update to device list', () => __awaiter(void 0, void 0, void 0, function* () {
123
+ // create bunch of devices using loop
124
+ const newDeviceList = [];
125
+ for (let i = 0; i < 10; i++) {
126
+ newDeviceList.push({
127
+ busy: false,
128
+ state: 'device',
129
+ udid: `emulator-${i}`,
130
+ platform: 'android',
131
+ offline: false,
132
+ host: '127.0.0.1',
133
+ });
134
+ }
135
+ // create a function to add new device with random delay to simulate concurrent calls from multiple nodes
136
+ const delayedAddDevice = (newDeviceList) => __awaiter(void 0, void 0, void 0, function* () {
137
+ yield new Promise((resolve) => setTimeout(resolve, Math.random() * 1000));
138
+ for (const device of newDeviceList) {
139
+ yield new Promise((resolve) => setTimeout(resolve, Math.random() * 1000));
140
+ yield (0, device_service_2.addNewDevice)([device]);
141
+ }
142
+ });
143
+ const existingDevices = yield (0, device_service_1.getAllDevices)();
144
+ // create some parallel calls to addNewDevice
145
+ yield Promise.all([delayedAddDevice(newDeviceList), delayedAddDevice(existingDevices)]);
146
+ // verify that all devices are added to the db
147
+ const updatedDeviceList = (yield db_1.XenonDatabase.DeviceModel)
148
+ .chain()
149
+ .find({ platform: 'android' })
150
+ .data();
151
+ // every newDeviceList should be listed under updatedDeviceList
152
+ // map udid only to make it simple
153
+ const addedDeviceUdids = newDeviceList.map((device) => device.udid);
154
+ const updatedDeviceUdids = updatedDeviceList.map((device) => device.udid);
155
+ addedDeviceUdids.forEach((udid) => updatedDeviceUdids.includes(udid).should.be.true);
156
+ }));
157
+ }));