@sqaitech/webdriver 0.30.10

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Bytedance, Inc. and its affiliates.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,293 @@
1
+ import { exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { DEFAULT_WDA_PORT } from "@sqaitech/shared/constants";
4
+ import { getDebug } from "@sqaitech/shared/logger";
5
+ function _define_property(obj, key, value) {
6
+ if (key in obj) Object.defineProperty(obj, key, {
7
+ value: value,
8
+ enumerable: true,
9
+ configurable: true,
10
+ writable: true
11
+ });
12
+ else obj[key] = value;
13
+ return obj;
14
+ }
15
+ class BaseServiceManager {
16
+ async restart() {
17
+ if (this.isRunning()) await this.stop();
18
+ await this.start();
19
+ }
20
+ getEndpoint() {
21
+ return `http://${this.host}:${this.port}`;
22
+ }
23
+ getPort() {
24
+ return this.port;
25
+ }
26
+ getHost() {
27
+ return this.host;
28
+ }
29
+ constructor(port, host = 'localhost'){
30
+ _define_property(this, "port", void 0);
31
+ _define_property(this, "host", void 0);
32
+ this.port = port;
33
+ this.host = host;
34
+ }
35
+ }
36
+ function WDAManager_define_property(obj, key, value) {
37
+ if (key in obj) Object.defineProperty(obj, key, {
38
+ value: value,
39
+ enumerable: true,
40
+ configurable: true,
41
+ writable: true
42
+ });
43
+ else obj[key] = value;
44
+ return obj;
45
+ }
46
+ const execAsync = promisify(exec);
47
+ const debugWDA = getDebug('webdriver:wda-manager');
48
+ class WDAManager extends BaseServiceManager {
49
+ static getInstance(port = DEFAULT_WDA_PORT, host) {
50
+ const key = `${host || 'localhost'}:${port}`;
51
+ if (!WDAManager.instances.has(key)) WDAManager.instances.set(key, new WDAManager({
52
+ port,
53
+ host
54
+ }));
55
+ return WDAManager.instances.get(key);
56
+ }
57
+ async start() {
58
+ if (this.isStarted) return void debugWDA(`WDA already started on ${this.config.host}:${this.config.port}`);
59
+ try {
60
+ if (await this.isWDARunning()) {
61
+ debugWDA(`WDA already running on port ${this.config.port}`);
62
+ this.isStarted = true;
63
+ return;
64
+ }
65
+ await this.startWDA();
66
+ await this.waitForWDA();
67
+ this.isStarted = true;
68
+ debugWDA(`WDA started successfully on ${this.config.host}:${this.config.port}`);
69
+ } catch (error) {
70
+ debugWDA(`Failed to start WDA: ${error}`);
71
+ throw new Error(`Failed to start WebDriverAgent: ${error}`);
72
+ }
73
+ }
74
+ async stop() {
75
+ if (!this.isStarted) return;
76
+ try {
77
+ this.isStarted = false;
78
+ debugWDA(`WDA stopped on ${this.config.host}:${this.config.port}`);
79
+ } catch (error) {
80
+ debugWDA(`Error stopping WDA: ${error}`);
81
+ }
82
+ }
83
+ isRunning() {
84
+ return this.isStarted;
85
+ }
86
+ async startWDA() {
87
+ await this.checkWDAPreparation();
88
+ debugWDA('WebDriverAgent verification completed');
89
+ }
90
+ async checkWDAPreparation() {
91
+ if (await this.isWDARunning()) return void debugWDA(`WebDriverAgent is already running on port ${this.config.port}`);
92
+ throw new Error(`WebDriverAgent is not running on ${this.config.host}:${this.config.port}. Please start WebDriverAgent manually:
93
+
94
+ \u{1F527} Setup Instructions:
95
+ 1. Install WebDriverAgent: npm install appium-webdriveragent
96
+ 2. Build and run WebDriverAgent:
97
+ - For simulators: Use Xcode to run WebDriverAgentRunner on your target simulator
98
+ - For real devices: Build WebDriverAgentRunner and install on your device
99
+ 3. Ensure WebDriverAgent is listening on ${this.config.host}:${this.config.port}
100
+
101
+ \u{1F4A1} Alternative: You can also specify a different host/port where WebDriverAgent is running.`);
102
+ }
103
+ async isWDARunning() {
104
+ try {
105
+ const url = `http://${this.config.host}:${this.config.port}/status`;
106
+ const response = await fetch(url);
107
+ if (!response.ok) return false;
108
+ const responseText = await response.text();
109
+ return responseText.includes('sessionId');
110
+ } catch (error) {
111
+ return false;
112
+ }
113
+ }
114
+ async waitForWDA(timeout = 30000) {
115
+ const startTime = Date.now();
116
+ while(Date.now() - startTime < timeout){
117
+ if (await this.isWDARunning()) return;
118
+ await new Promise((resolve)=>setTimeout(resolve, 1000));
119
+ }
120
+ throw new Error(`WebDriverAgent did not start within ${timeout}ms`);
121
+ }
122
+ async killWDAProcesses() {
123
+ try {
124
+ await execAsync('pkill -f "xcodebuild.*WebDriverAgent"').catch(()=>{});
125
+ await execAsync('pkill -f "WebDriverAgentRunner"').catch(()=>{});
126
+ debugWDA('Killed WDA processes');
127
+ } catch (error) {}
128
+ }
129
+ constructor(config){
130
+ super(config.port, config.host), WDAManager_define_property(this, "config", void 0), WDAManager_define_property(this, "isStarted", false);
131
+ this.config = {
132
+ bundleId: 'com.apple.WebDriverAgentRunner.xctrunner',
133
+ usePrebuiltWDA: true,
134
+ host: 'localhost',
135
+ ...config,
136
+ port: config.port || DEFAULT_WDA_PORT
137
+ };
138
+ }
139
+ }
140
+ WDAManager_define_property(WDAManager, "instances", new Map());
141
+ function request_define_property(obj, key, value) {
142
+ if (key in obj) Object.defineProperty(obj, key, {
143
+ value: value,
144
+ enumerable: true,
145
+ configurable: true,
146
+ writable: true
147
+ });
148
+ else obj[key] = value;
149
+ return obj;
150
+ }
151
+ const debugRequest = getDebug('webdriver:request');
152
+ class WebDriverRequestError extends Error {
153
+ constructor(message, status, response){
154
+ super(message), request_define_property(this, "status", void 0), request_define_property(this, "response", void 0), this.status = status, this.response = response;
155
+ this.name = 'WebDriverRequestError';
156
+ }
157
+ }
158
+ async function makeWebDriverRequest(baseUrl, method, endpoint, data, timeout = 30000) {
159
+ const url = `${baseUrl}${endpoint}`;
160
+ debugRequest(`${method} ${url}${data ? ` with data: ${JSON.stringify(data)}` : ''}`);
161
+ const controller = new AbortController();
162
+ const timeoutId = setTimeout(()=>controller.abort(), timeout);
163
+ try {
164
+ const response = await fetch(url, {
165
+ method,
166
+ headers: {
167
+ 'Content-Type': 'application/json',
168
+ Accept: 'application/json'
169
+ },
170
+ body: data ? JSON.stringify(data) : void 0,
171
+ signal: controller.signal
172
+ });
173
+ clearTimeout(timeoutId);
174
+ let responseData;
175
+ const contentType = response.headers.get('content-type');
176
+ if (null == contentType ? void 0 : contentType.includes('application/json')) responseData = await response.json();
177
+ else {
178
+ const textData = await response.text();
179
+ responseData = textData;
180
+ }
181
+ if (!response.ok) {
182
+ const errorMessage = (null == responseData ? void 0 : responseData.error) || (null == responseData ? void 0 : responseData.message) || `HTTP ${response.status}`;
183
+ throw new WebDriverRequestError(`WebDriver request failed: ${errorMessage}`, response.status, responseData);
184
+ }
185
+ return responseData;
186
+ } catch (error) {
187
+ clearTimeout(timeoutId);
188
+ if (error instanceof WebDriverRequestError) throw error;
189
+ if (error instanceof Error && 'AbortError' === error.name) throw new WebDriverRequestError(`Request timeout after ${timeout}ms`);
190
+ debugRequest(`Request failed: ${error}`);
191
+ throw new WebDriverRequestError(`Request failed: ${error}`);
192
+ }
193
+ }
194
+ function WebDriverClient_define_property(obj, key, value) {
195
+ if (key in obj) Object.defineProperty(obj, key, {
196
+ value: value,
197
+ enumerable: true,
198
+ configurable: true,
199
+ writable: true
200
+ });
201
+ else obj[key] = value;
202
+ return obj;
203
+ }
204
+ const debugClient = getDebug('webdriver:client');
205
+ class WebDriverClient {
206
+ get sessionInfo() {
207
+ if (!this.sessionId) return null;
208
+ return {
209
+ sessionId: this.sessionId,
210
+ capabilities: {}
211
+ };
212
+ }
213
+ async createSession(capabilities) {
214
+ try {
215
+ var _response_value, _response_value1;
216
+ const response = await this.makeRequest('POST', '/session', {
217
+ capabilities: {
218
+ alwaysMatch: {
219
+ ...capabilities
220
+ }
221
+ }
222
+ });
223
+ this.sessionId = response.sessionId || (null == (_response_value = response.value) ? void 0 : _response_value.sessionId);
224
+ if (!this.sessionId) throw new Error('Failed to get session ID from response');
225
+ debugClient(`Created session: ${this.sessionId}`);
226
+ return {
227
+ sessionId: this.sessionId,
228
+ capabilities: response.capabilities || (null == (_response_value1 = response.value) ? void 0 : _response_value1.capabilities) || {}
229
+ };
230
+ } catch (error) {
231
+ debugClient(`Failed to create session: ${error}`);
232
+ throw error;
233
+ }
234
+ }
235
+ async deleteSession() {
236
+ if (!this.sessionId) return void debugClient('No active session to delete');
237
+ try {
238
+ await this.makeRequest('DELETE', `/session/${this.sessionId}`);
239
+ debugClient(`Deleted session: ${this.sessionId}`);
240
+ this.sessionId = null;
241
+ } catch (error) {
242
+ debugClient(`Failed to delete session: ${error}`);
243
+ this.sessionId = null;
244
+ }
245
+ }
246
+ async takeScreenshot() {
247
+ this.ensureSession();
248
+ const response = await this.makeRequest('GET', `/session/${this.sessionId}/screenshot`);
249
+ return response.value || response;
250
+ }
251
+ async getWindowSize() {
252
+ this.ensureSession();
253
+ const response = await this.makeRequest('GET', `/session/${this.sessionId}/window/rect`);
254
+ const rect = response.value || response;
255
+ return {
256
+ width: rect.width,
257
+ height: rect.height
258
+ };
259
+ }
260
+ async getDeviceInfo() {
261
+ try {
262
+ const statusResponse = await this.makeRequest('GET', '/status');
263
+ if (null == statusResponse ? void 0 : statusResponse.device) return {
264
+ udid: statusResponse.device.udid || statusResponse.device.identifier || '',
265
+ name: statusResponse.device.name || '',
266
+ model: statusResponse.device.model || statusResponse.device.productName || ''
267
+ };
268
+ return null;
269
+ } catch (error) {
270
+ debugClient(`Failed to get device info: ${error}`);
271
+ return null;
272
+ }
273
+ }
274
+ async makeRequest(method, endpoint, data) {
275
+ return makeWebDriverRequest(this.baseUrl, method, endpoint, data, this.timeout);
276
+ }
277
+ ensureSession() {
278
+ if (!this.sessionId) throw new Error('No active WebDriver session. Call createSession() first.');
279
+ }
280
+ constructor(options = {}){
281
+ WebDriverClient_define_property(this, "baseUrl", void 0);
282
+ WebDriverClient_define_property(this, "sessionId", null);
283
+ WebDriverClient_define_property(this, "port", void 0);
284
+ WebDriverClient_define_property(this, "host", void 0);
285
+ WebDriverClient_define_property(this, "timeout", void 0);
286
+ this.port = options.port || DEFAULT_WDA_PORT;
287
+ this.host = options.host || 'localhost';
288
+ this.timeout = options.timeout || 30000;
289
+ this.baseUrl = `http://${this.host}:${this.port}`;
290
+ debugClient(`Initialized WebDriver client on ${this.host}:${this.port}`);
291
+ }
292
+ }
293
+ export { BaseServiceManager, WDAManager, WebDriverClient, WebDriverRequestError, makeWebDriverRequest };
@@ -0,0 +1,339 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ WebDriverRequestError: ()=>WebDriverRequestError,
28
+ WDAManager: ()=>WDAManager,
29
+ WebDriverClient: ()=>WebDriverClient,
30
+ BaseServiceManager: ()=>BaseServiceManager,
31
+ makeWebDriverRequest: ()=>makeWebDriverRequest
32
+ });
33
+ function _define_property(obj, key, value) {
34
+ if (key in obj) Object.defineProperty(obj, key, {
35
+ value: value,
36
+ enumerable: true,
37
+ configurable: true,
38
+ writable: true
39
+ });
40
+ else obj[key] = value;
41
+ return obj;
42
+ }
43
+ class BaseServiceManager {
44
+ async restart() {
45
+ if (this.isRunning()) await this.stop();
46
+ await this.start();
47
+ }
48
+ getEndpoint() {
49
+ return `http://${this.host}:${this.port}`;
50
+ }
51
+ getPort() {
52
+ return this.port;
53
+ }
54
+ getHost() {
55
+ return this.host;
56
+ }
57
+ constructor(port, host = 'localhost'){
58
+ _define_property(this, "port", void 0);
59
+ _define_property(this, "host", void 0);
60
+ this.port = port;
61
+ this.host = host;
62
+ }
63
+ }
64
+ const external_node_child_process_namespaceObject = require("node:child_process");
65
+ const external_node_util_namespaceObject = require("node:util");
66
+ const constants_namespaceObject = require("@sqaitech/shared/constants");
67
+ const logger_namespaceObject = require("@sqaitech/shared/logger");
68
+ function WDAManager_define_property(obj, key, value) {
69
+ if (key in obj) Object.defineProperty(obj, key, {
70
+ value: value,
71
+ enumerable: true,
72
+ configurable: true,
73
+ writable: true
74
+ });
75
+ else obj[key] = value;
76
+ return obj;
77
+ }
78
+ const execAsync = (0, external_node_util_namespaceObject.promisify)(external_node_child_process_namespaceObject.exec);
79
+ const debugWDA = (0, logger_namespaceObject.getDebug)('webdriver:wda-manager');
80
+ class WDAManager extends BaseServiceManager {
81
+ static getInstance(port = constants_namespaceObject.DEFAULT_WDA_PORT, host) {
82
+ const key = `${host || 'localhost'}:${port}`;
83
+ if (!WDAManager.instances.has(key)) WDAManager.instances.set(key, new WDAManager({
84
+ port,
85
+ host
86
+ }));
87
+ return WDAManager.instances.get(key);
88
+ }
89
+ async start() {
90
+ if (this.isStarted) return void debugWDA(`WDA already started on ${this.config.host}:${this.config.port}`);
91
+ try {
92
+ if (await this.isWDARunning()) {
93
+ debugWDA(`WDA already running on port ${this.config.port}`);
94
+ this.isStarted = true;
95
+ return;
96
+ }
97
+ await this.startWDA();
98
+ await this.waitForWDA();
99
+ this.isStarted = true;
100
+ debugWDA(`WDA started successfully on ${this.config.host}:${this.config.port}`);
101
+ } catch (error) {
102
+ debugWDA(`Failed to start WDA: ${error}`);
103
+ throw new Error(`Failed to start WebDriverAgent: ${error}`);
104
+ }
105
+ }
106
+ async stop() {
107
+ if (!this.isStarted) return;
108
+ try {
109
+ this.isStarted = false;
110
+ debugWDA(`WDA stopped on ${this.config.host}:${this.config.port}`);
111
+ } catch (error) {
112
+ debugWDA(`Error stopping WDA: ${error}`);
113
+ }
114
+ }
115
+ isRunning() {
116
+ return this.isStarted;
117
+ }
118
+ async startWDA() {
119
+ await this.checkWDAPreparation();
120
+ debugWDA('WebDriverAgent verification completed');
121
+ }
122
+ async checkWDAPreparation() {
123
+ if (await this.isWDARunning()) return void debugWDA(`WebDriverAgent is already running on port ${this.config.port}`);
124
+ throw new Error(`WebDriverAgent is not running on ${this.config.host}:${this.config.port}. Please start WebDriverAgent manually:
125
+
126
+ \u{1F527} Setup Instructions:
127
+ 1. Install WebDriverAgent: npm install appium-webdriveragent
128
+ 2. Build and run WebDriverAgent:
129
+ - For simulators: Use Xcode to run WebDriverAgentRunner on your target simulator
130
+ - For real devices: Build WebDriverAgentRunner and install on your device
131
+ 3. Ensure WebDriverAgent is listening on ${this.config.host}:${this.config.port}
132
+
133
+ \u{1F4A1} Alternative: You can also specify a different host/port where WebDriverAgent is running.`);
134
+ }
135
+ async isWDARunning() {
136
+ try {
137
+ const url = `http://${this.config.host}:${this.config.port}/status`;
138
+ const response = await fetch(url);
139
+ if (!response.ok) return false;
140
+ const responseText = await response.text();
141
+ return responseText.includes('sessionId');
142
+ } catch (error) {
143
+ return false;
144
+ }
145
+ }
146
+ async waitForWDA(timeout = 30000) {
147
+ const startTime = Date.now();
148
+ while(Date.now() - startTime < timeout){
149
+ if (await this.isWDARunning()) return;
150
+ await new Promise((resolve)=>setTimeout(resolve, 1000));
151
+ }
152
+ throw new Error(`WebDriverAgent did not start within ${timeout}ms`);
153
+ }
154
+ async killWDAProcesses() {
155
+ try {
156
+ await execAsync('pkill -f "xcodebuild.*WebDriverAgent"').catch(()=>{});
157
+ await execAsync('pkill -f "WebDriverAgentRunner"').catch(()=>{});
158
+ debugWDA('Killed WDA processes');
159
+ } catch (error) {}
160
+ }
161
+ constructor(config){
162
+ super(config.port, config.host), WDAManager_define_property(this, "config", void 0), WDAManager_define_property(this, "isStarted", false);
163
+ this.config = {
164
+ bundleId: 'com.apple.WebDriverAgentRunner.xctrunner',
165
+ usePrebuiltWDA: true,
166
+ host: 'localhost',
167
+ ...config,
168
+ port: config.port || constants_namespaceObject.DEFAULT_WDA_PORT
169
+ };
170
+ }
171
+ }
172
+ WDAManager_define_property(WDAManager, "instances", new Map());
173
+ function request_define_property(obj, key, value) {
174
+ if (key in obj) Object.defineProperty(obj, key, {
175
+ value: value,
176
+ enumerable: true,
177
+ configurable: true,
178
+ writable: true
179
+ });
180
+ else obj[key] = value;
181
+ return obj;
182
+ }
183
+ const debugRequest = (0, logger_namespaceObject.getDebug)('webdriver:request');
184
+ class WebDriverRequestError extends Error {
185
+ constructor(message, status, response){
186
+ super(message), request_define_property(this, "status", void 0), request_define_property(this, "response", void 0), this.status = status, this.response = response;
187
+ this.name = 'WebDriverRequestError';
188
+ }
189
+ }
190
+ async function makeWebDriverRequest(baseUrl, method, endpoint, data, timeout = 30000) {
191
+ const url = `${baseUrl}${endpoint}`;
192
+ debugRequest(`${method} ${url}${data ? ` with data: ${JSON.stringify(data)}` : ''}`);
193
+ const controller = new AbortController();
194
+ const timeoutId = setTimeout(()=>controller.abort(), timeout);
195
+ try {
196
+ const response = await fetch(url, {
197
+ method,
198
+ headers: {
199
+ 'Content-Type': 'application/json',
200
+ Accept: 'application/json'
201
+ },
202
+ body: data ? JSON.stringify(data) : void 0,
203
+ signal: controller.signal
204
+ });
205
+ clearTimeout(timeoutId);
206
+ let responseData;
207
+ const contentType = response.headers.get('content-type');
208
+ if (null == contentType ? void 0 : contentType.includes('application/json')) responseData = await response.json();
209
+ else {
210
+ const textData = await response.text();
211
+ responseData = textData;
212
+ }
213
+ if (!response.ok) {
214
+ const errorMessage = (null == responseData ? void 0 : responseData.error) || (null == responseData ? void 0 : responseData.message) || `HTTP ${response.status}`;
215
+ throw new WebDriverRequestError(`WebDriver request failed: ${errorMessage}`, response.status, responseData);
216
+ }
217
+ return responseData;
218
+ } catch (error) {
219
+ clearTimeout(timeoutId);
220
+ if (error instanceof WebDriverRequestError) throw error;
221
+ if (error instanceof Error && 'AbortError' === error.name) throw new WebDriverRequestError(`Request timeout after ${timeout}ms`);
222
+ debugRequest(`Request failed: ${error}`);
223
+ throw new WebDriverRequestError(`Request failed: ${error}`);
224
+ }
225
+ }
226
+ function WebDriverClient_define_property(obj, key, value) {
227
+ if (key in obj) Object.defineProperty(obj, key, {
228
+ value: value,
229
+ enumerable: true,
230
+ configurable: true,
231
+ writable: true
232
+ });
233
+ else obj[key] = value;
234
+ return obj;
235
+ }
236
+ const debugClient = (0, logger_namespaceObject.getDebug)('webdriver:client');
237
+ class WebDriverClient {
238
+ get sessionInfo() {
239
+ if (!this.sessionId) return null;
240
+ return {
241
+ sessionId: this.sessionId,
242
+ capabilities: {}
243
+ };
244
+ }
245
+ async createSession(capabilities) {
246
+ try {
247
+ var _response_value, _response_value1;
248
+ const response = await this.makeRequest('POST', '/session', {
249
+ capabilities: {
250
+ alwaysMatch: {
251
+ ...capabilities
252
+ }
253
+ }
254
+ });
255
+ this.sessionId = response.sessionId || (null == (_response_value = response.value) ? void 0 : _response_value.sessionId);
256
+ if (!this.sessionId) throw new Error('Failed to get session ID from response');
257
+ debugClient(`Created session: ${this.sessionId}`);
258
+ return {
259
+ sessionId: this.sessionId,
260
+ capabilities: response.capabilities || (null == (_response_value1 = response.value) ? void 0 : _response_value1.capabilities) || {}
261
+ };
262
+ } catch (error) {
263
+ debugClient(`Failed to create session: ${error}`);
264
+ throw error;
265
+ }
266
+ }
267
+ async deleteSession() {
268
+ if (!this.sessionId) return void debugClient('No active session to delete');
269
+ try {
270
+ await this.makeRequest('DELETE', `/session/${this.sessionId}`);
271
+ debugClient(`Deleted session: ${this.sessionId}`);
272
+ this.sessionId = null;
273
+ } catch (error) {
274
+ debugClient(`Failed to delete session: ${error}`);
275
+ this.sessionId = null;
276
+ }
277
+ }
278
+ async takeScreenshot() {
279
+ this.ensureSession();
280
+ const response = await this.makeRequest('GET', `/session/${this.sessionId}/screenshot`);
281
+ return response.value || response;
282
+ }
283
+ async getWindowSize() {
284
+ this.ensureSession();
285
+ const response = await this.makeRequest('GET', `/session/${this.sessionId}/window/rect`);
286
+ const rect = response.value || response;
287
+ return {
288
+ width: rect.width,
289
+ height: rect.height
290
+ };
291
+ }
292
+ async getDeviceInfo() {
293
+ try {
294
+ const statusResponse = await this.makeRequest('GET', '/status');
295
+ if (null == statusResponse ? void 0 : statusResponse.device) return {
296
+ udid: statusResponse.device.udid || statusResponse.device.identifier || '',
297
+ name: statusResponse.device.name || '',
298
+ model: statusResponse.device.model || statusResponse.device.productName || ''
299
+ };
300
+ return null;
301
+ } catch (error) {
302
+ debugClient(`Failed to get device info: ${error}`);
303
+ return null;
304
+ }
305
+ }
306
+ async makeRequest(method, endpoint, data) {
307
+ return makeWebDriverRequest(this.baseUrl, method, endpoint, data, this.timeout);
308
+ }
309
+ ensureSession() {
310
+ if (!this.sessionId) throw new Error('No active WebDriver session. Call createSession() first.');
311
+ }
312
+ constructor(options = {}){
313
+ WebDriverClient_define_property(this, "baseUrl", void 0);
314
+ WebDriverClient_define_property(this, "sessionId", null);
315
+ WebDriverClient_define_property(this, "port", void 0);
316
+ WebDriverClient_define_property(this, "host", void 0);
317
+ WebDriverClient_define_property(this, "timeout", void 0);
318
+ this.port = options.port || constants_namespaceObject.DEFAULT_WDA_PORT;
319
+ this.host = options.host || 'localhost';
320
+ this.timeout = options.timeout || 30000;
321
+ this.baseUrl = `http://${this.host}:${this.port}`;
322
+ debugClient(`Initialized WebDriver client on ${this.host}:${this.port}`);
323
+ }
324
+ }
325
+ exports.BaseServiceManager = __webpack_exports__.BaseServiceManager;
326
+ exports.WDAManager = __webpack_exports__.WDAManager;
327
+ exports.WebDriverClient = __webpack_exports__.WebDriverClient;
328
+ exports.WebDriverRequestError = __webpack_exports__.WebDriverRequestError;
329
+ exports.makeWebDriverRequest = __webpack_exports__.makeWebDriverRequest;
330
+ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
331
+ "BaseServiceManager",
332
+ "WDAManager",
333
+ "WebDriverClient",
334
+ "WebDriverRequestError",
335
+ "makeWebDriverRequest"
336
+ ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
337
+ Object.defineProperty(exports, '__esModule', {
338
+ value: true
339
+ });
@@ -0,0 +1,122 @@
1
+ import { WEBDRIVER_ELEMENT_ID_KEY } from '@sqaitech/shared/constants';
2
+
3
+ export declare abstract class BaseServiceManager implements WebDriverServiceManager {
4
+ protected port: number;
5
+ protected host: string;
6
+ constructor(port: number, host?: string);
7
+ abstract start(): Promise<void>;
8
+ abstract stop(): Promise<void>;
9
+ abstract isRunning(): boolean;
10
+ restart(): Promise<void>;
11
+ getEndpoint(): string;
12
+ getPort(): number;
13
+ getHost(): string;
14
+ }
15
+
16
+ export declare interface DeviceInfo {
17
+ udid: string;
18
+ name: string;
19
+ model: string;
20
+ }
21
+
22
+ export declare function makeWebDriverRequest(baseUrl: string, method: string, endpoint: string, data?: any, timeout?: number): Promise<any>;
23
+
24
+ export declare interface Point {
25
+ x: number;
26
+ y: number;
27
+ }
28
+
29
+ export declare interface Size {
30
+ width: number;
31
+ height: number;
32
+ }
33
+
34
+ export declare interface WDAConfig {
35
+ port: number;
36
+ host?: string;
37
+ wdaPath?: string;
38
+ bundleId?: string;
39
+ usePrebuiltWDA?: boolean;
40
+ }
41
+
42
+ export declare interface WDAElement {
43
+ ELEMENT: string;
44
+ [WEBDRIVER_ELEMENT_ID_KEY]: string;
45
+ }
46
+
47
+ export declare interface WDAElementInfo {
48
+ type: string;
49
+ name: string;
50
+ label: string;
51
+ value: string;
52
+ rect: {
53
+ x: number;
54
+ y: number;
55
+ width: number;
56
+ height: number;
57
+ };
58
+ enabled: boolean;
59
+ visible: boolean;
60
+ }
61
+
62
+ export declare class WDAManager extends BaseServiceManager {
63
+ private static instances;
64
+ private config;
65
+ private isStarted;
66
+ private constructor();
67
+ static getInstance(port?: number, host?: string): WDAManager;
68
+ start(): Promise<void>;
69
+ stop(): Promise<void>;
70
+ isRunning(): boolean;
71
+ private startWDA;
72
+ private checkWDAPreparation;
73
+ private isWDARunning;
74
+ private waitForWDA;
75
+ private killWDAProcesses;
76
+ }
77
+
78
+ export declare interface WDASession {
79
+ sessionId: string;
80
+ capabilities: Record<string, any>;
81
+ }
82
+
83
+ export declare class WebDriverClient {
84
+ protected baseUrl: string;
85
+ protected sessionId: string | null;
86
+ protected port: number;
87
+ protected host: string;
88
+ protected timeout: number;
89
+ constructor(options?: WebDriverOptions);
90
+ get sessionInfo(): WDASession | null;
91
+ createSession(capabilities?: any): Promise<WDASession>;
92
+ deleteSession(): Promise<void>;
93
+ takeScreenshot(): Promise<string>;
94
+ getWindowSize(): Promise<Size>;
95
+ getDeviceInfo(): Promise<DeviceInfo | null>;
96
+ protected makeRequest(method: string, endpoint: string, data?: any): Promise<any>;
97
+ protected ensureSession(): void;
98
+ }
99
+
100
+ export declare interface WebDriverOptions {
101
+ port?: number;
102
+ host?: string;
103
+ timeout?: number;
104
+ }
105
+
106
+ export declare class WebDriverRequestError extends Error {
107
+ status?: number | undefined;
108
+ response?: any | undefined;
109
+ constructor(message: string, status?: number | undefined, response?: any | undefined);
110
+ }
111
+
112
+ export declare interface WebDriverServiceManager {
113
+ start(): Promise<void>;
114
+ stop(): Promise<void>;
115
+ restart(): Promise<void>;
116
+ isRunning(): boolean;
117
+ getEndpoint(): string;
118
+ getPort(): number;
119
+ getHost(): string;
120
+ }
121
+
122
+ export { }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@sqaitech/webdriver",
3
+ "version": "0.30.10",
4
+ "description": "WebDriver protocol implementation for SQAI automation",
5
+ "main": "dist/lib/index.js",
6
+ "module": "dist/es/index.mjs",
7
+ "types": "dist/types/index.d.ts",
8
+ "dependencies": {
9
+ "node-fetch": "^3.3.2",
10
+ "@sqaitech/shared": "0.30.10"
11
+ },
12
+ "devDependencies": {
13
+ "@rslib/core": "^0.11.2",
14
+ "@types/node": "^18.0.0",
15
+ "typescript": "^5.8.3",
16
+ "vitest": "3.0.5"
17
+ },
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/types/index.d.ts",
21
+ "import": "./dist/es/index.mjs",
22
+ "require": "./dist/lib/index.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "keywords": [
29
+ "webdriver",
30
+ "automation",
31
+ "ios",
32
+ "mobile"
33
+ ],
34
+ "scripts": {
35
+ "build": "rslib build",
36
+ "dev": "rslib build --watch",
37
+ "test": "vitest",
38
+ "lint": "biome check .",
39
+ "lint:fix": "biome check . --write"
40
+ }
41
+ }