@qawolf/run-globals-ios 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +232 -0
- package/dist/audio.d.ts +98 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/audio.js +145 -0
- package/dist/audio.js.map +1 -0
- package/dist/barcode.d.ts +58 -0
- package/dist/barcode.d.ts.map +1 -0
- package/dist/barcode.js +45 -0
- package/dist/barcode.js.map +1 -0
- package/dist/beacon.d.ts +48 -0
- package/dist/beacon.d.ts.map +1 -0
- package/dist/beacon.js +49 -0
- package/dist/beacon.js.map +1 -0
- package/dist/configuration-profile.d.ts +27 -0
- package/dist/configuration-profile.d.ts.map +1 -0
- package/dist/configuration-profile.js +40 -0
- package/dist/configuration-profile.js.map +1 -0
- package/dist/gateway.d.ts +443 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +433 -0
- package/dist/gateway.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/injectionHelpers.d.ts +18 -0
- package/dist/injectionHelpers.d.ts.map +1 -0
- package/dist/injectionHelpers.js +68 -0
- package/dist/injectionHelpers.js.map +1 -0
- package/dist/media.d.ts +79 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +82 -0
- package/dist/media.js.map +1 -0
- package/dist/photo.d.ts +117 -0
- package/dist/photo.d.ts.map +1 -0
- package/dist/photo.js +143 -0
- package/dist/photo.js.map +1 -0
- package/dist/typings.d.ts +773 -0
- package/dist/webview.d.ts +23 -0
- package/dist/webview.d.ts.map +1 -0
- package/dist/webview.js +25 -0
- package/dist/webview.js.map +1 -0
- package/package.json +68 -0
package/dist/gateway.js
ADDED
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Schemas
|
|
5
|
+
// ============================================================================
|
|
6
|
+
export const RouteTypeSchema = z.enum([
|
|
7
|
+
"direct",
|
|
8
|
+
"http-proxy",
|
|
9
|
+
"wireguard",
|
|
10
|
+
"openvpn",
|
|
11
|
+
"relay",
|
|
12
|
+
]);
|
|
13
|
+
export const TunnelStatusSchema = z.enum(["down", "starting", "up", "error"]);
|
|
14
|
+
export const TunnelStateSchema = z.object({
|
|
15
|
+
status: TunnelStatusSchema,
|
|
16
|
+
interface: z.string().optional(),
|
|
17
|
+
error: z.string().optional(),
|
|
18
|
+
});
|
|
19
|
+
export const TunnelStatusMapSchema = z.record(z.string(), TunnelStateSchema);
|
|
20
|
+
// Validation helpers
|
|
21
|
+
const HostSchema = z
|
|
22
|
+
.string()
|
|
23
|
+
.min(1, "Host must not be empty")
|
|
24
|
+
.refine((h) => !h.includes(":"), {
|
|
25
|
+
message: "Host must be a hostname or IP without scheme or port (e.g. 'proxy.example.com', not 'http://proxy.example.com:8080')",
|
|
26
|
+
});
|
|
27
|
+
const PortSchema = z.number().int().min(1).max(65535);
|
|
28
|
+
// Tunnel configuration schemas
|
|
29
|
+
export const HttpProxyTunnelSchema = z.object({
|
|
30
|
+
type: z.literal("http-proxy"),
|
|
31
|
+
host: HostSchema,
|
|
32
|
+
port: PortSchema,
|
|
33
|
+
username: z.string().optional(),
|
|
34
|
+
password: z.string().optional(),
|
|
35
|
+
});
|
|
36
|
+
export const WireGuardTunnelSchema = z.object({
|
|
37
|
+
type: z.literal("wireguard"),
|
|
38
|
+
/** Path to WireGuard configuration file (.conf) */
|
|
39
|
+
configPath: z.string(),
|
|
40
|
+
});
|
|
41
|
+
export const OpenVPNTunnelSchema = z.object({
|
|
42
|
+
type: z.literal("openvpn"),
|
|
43
|
+
/** Path to OpenVPN configuration file (.ovpn) */
|
|
44
|
+
configPath: z.string(),
|
|
45
|
+
});
|
|
46
|
+
export const RelayTunnelSchema = z.object({
|
|
47
|
+
type: z.literal("relay"),
|
|
48
|
+
host: HostSchema,
|
|
49
|
+
port: PortSchema,
|
|
50
|
+
username: z.string(),
|
|
51
|
+
password: z.string(),
|
|
52
|
+
/** Transport type (default: tls) */
|
|
53
|
+
dialer: z.enum(["tls", "tcp"]).optional(),
|
|
54
|
+
/** TLS certificate verification (default: true, only applies to tls dialer) */
|
|
55
|
+
secure: z.boolean().optional(),
|
|
56
|
+
});
|
|
57
|
+
export const DirectTunnelSchema = z.object({
|
|
58
|
+
type: z.literal("direct"),
|
|
59
|
+
});
|
|
60
|
+
export const TunnelConfigSchema = z.union([
|
|
61
|
+
DirectTunnelSchema,
|
|
62
|
+
HttpProxyTunnelSchema,
|
|
63
|
+
WireGuardTunnelSchema,
|
|
64
|
+
OpenVPNTunnelSchema,
|
|
65
|
+
RelayTunnelSchema,
|
|
66
|
+
]);
|
|
67
|
+
export const RouteTrafficConfigSchema = z.object({
|
|
68
|
+
/** Bundle IDs of apps whose traffic to route */
|
|
69
|
+
apps: z.array(z.string()),
|
|
70
|
+
/** Safari domains to route (supports wildcards like *.example.com) */
|
|
71
|
+
domains: z.array(z.string()).optional(),
|
|
72
|
+
/** Tunnel configuration */
|
|
73
|
+
tunnel: TunnelConfigSchema,
|
|
74
|
+
/**
|
|
75
|
+
* SOCKS5 proxy host for the VPN to connect to. Default: 172.20.10.1 (CDC NCM)
|
|
76
|
+
* This must be an IP address reachable from the iOS device.
|
|
77
|
+
* - Production/staging (K8s with CDC NCM): 172.20.10.1 (default)
|
|
78
|
+
* - Local development (Mac USB): Must pass 192.168.2.1 explicitly
|
|
79
|
+
* - Alternative: The Mac's WiFi IP if both devices are on the same network
|
|
80
|
+
*/
|
|
81
|
+
socksHost: HostSchema.optional(),
|
|
82
|
+
/**
|
|
83
|
+
* SOCKS5 proxy port. Default: 1080
|
|
84
|
+
*/
|
|
85
|
+
socksPort: PortSchema.optional(),
|
|
86
|
+
/**
|
|
87
|
+
* Enable MITM network inspection. When true, HTTPS traffic is decrypted
|
|
88
|
+
* and recorded for later retrieval via getNetworkLogs().
|
|
89
|
+
*/
|
|
90
|
+
inspect: z.boolean().optional(),
|
|
91
|
+
});
|
|
92
|
+
// Routing tables schema
|
|
93
|
+
export const RoutingTablesSchema = z.object({
|
|
94
|
+
/** Which routing table the ip rule currently points GOST traffic to */
|
|
95
|
+
activeTable: z.string(),
|
|
96
|
+
/** Entries in each routing table (direct, wireguard, openvpn) */
|
|
97
|
+
tables: z.record(z.string(), z.array(z.string())),
|
|
98
|
+
});
|
|
99
|
+
// Traffic stats schemas
|
|
100
|
+
export const RouteStatsSchema = z.object({
|
|
101
|
+
packets: z.number(),
|
|
102
|
+
bytes: z.number(),
|
|
103
|
+
});
|
|
104
|
+
export const InterfaceStatsSchema = z.object({
|
|
105
|
+
rxPackets: z.number(),
|
|
106
|
+
txPackets: z.number(),
|
|
107
|
+
rxBytes: z.number(),
|
|
108
|
+
txBytes: z.number(),
|
|
109
|
+
});
|
|
110
|
+
export const TrafficStatsSchema = z.object({
|
|
111
|
+
/** Per-route packet/byte counters (direct, http-proxy, wireguard, openvpn) */
|
|
112
|
+
routes: z.record(z.string(), RouteStatsSchema),
|
|
113
|
+
/** Per-interface packet/byte counters (eth0, tun0, wg0, etc.) */
|
|
114
|
+
interfaces: z.record(z.string(), InterfaceStatsSchema),
|
|
115
|
+
});
|
|
116
|
+
// Combined network status schema
|
|
117
|
+
export const NetworkStatusSchema = z.object({
|
|
118
|
+
/** Current active route */
|
|
119
|
+
route: RouteTypeSchema,
|
|
120
|
+
/** Status of all tunnels */
|
|
121
|
+
tunnels: TunnelStatusMapSchema,
|
|
122
|
+
/** Routing tables and which is active */
|
|
123
|
+
routingTables: RoutingTablesSchema.optional(),
|
|
124
|
+
/** Traffic counters per route and interface */
|
|
125
|
+
traffic: TrafficStatsSchema.optional(),
|
|
126
|
+
/** Per-app VPN app status */
|
|
127
|
+
vpnApp: z.object({
|
|
128
|
+
bundleId: z.string(),
|
|
129
|
+
installed: z.boolean(),
|
|
130
|
+
pid: z.number().optional(),
|
|
131
|
+
}),
|
|
132
|
+
/** Apps and domains being routed */
|
|
133
|
+
routedApps: z.array(z.string()),
|
|
134
|
+
routedDomains: z.array(z.string()),
|
|
135
|
+
});
|
|
136
|
+
// Network condition schemas
|
|
137
|
+
export const NetworkConditionConfigSchema = z
|
|
138
|
+
.object({
|
|
139
|
+
bandwidthKbps: z.number().positive().optional(),
|
|
140
|
+
latencyMs: z.number().nonnegative().optional(),
|
|
141
|
+
jitterMs: z.number().nonnegative().optional(),
|
|
142
|
+
packetLossPercent: z.number().min(0).max(100).optional(),
|
|
143
|
+
})
|
|
144
|
+
.refine((c) => !c.jitterMs || (c.latencyMs && c.latencyMs > 0), {
|
|
145
|
+
message: "latencyMs must be > 0 when jitterMs is specified",
|
|
146
|
+
path: ["latencyMs"],
|
|
147
|
+
});
|
|
148
|
+
/** 2G EDGE: ~240 Kbps, 300ms latency, high jitter */
|
|
149
|
+
export const NETWORK_2G_EDGE = {
|
|
150
|
+
bandwidthKbps: 240,
|
|
151
|
+
latencyMs: 300,
|
|
152
|
+
jitterMs: 100,
|
|
153
|
+
packetLossPercent: 1.5,
|
|
154
|
+
};
|
|
155
|
+
/** 3G: ~1.8 Mbps, 100ms latency */
|
|
156
|
+
export const NETWORK_3G = {
|
|
157
|
+
bandwidthKbps: 1800,
|
|
158
|
+
latencyMs: 100,
|
|
159
|
+
jitterMs: 30,
|
|
160
|
+
packetLossPercent: 0.5,
|
|
161
|
+
};
|
|
162
|
+
/** 4G LTE: ~12 Mbps, 30ms latency */
|
|
163
|
+
export const NETWORK_4G_LTE = {
|
|
164
|
+
bandwidthKbps: 12000,
|
|
165
|
+
latencyMs: 30,
|
|
166
|
+
jitterMs: 10,
|
|
167
|
+
packetLossPercent: 0.1,
|
|
168
|
+
};
|
|
169
|
+
/** 5G: ~100 Mbps, 10ms latency */
|
|
170
|
+
export const NETWORK_5G = {
|
|
171
|
+
bandwidthKbps: 100000,
|
|
172
|
+
latencyMs: 10,
|
|
173
|
+
jitterMs: 3,
|
|
174
|
+
packetLossPercent: 0.01,
|
|
175
|
+
};
|
|
176
|
+
/** Satellite: ~5 Mbps, 600ms latency */
|
|
177
|
+
export const NETWORK_SATELLITE = {
|
|
178
|
+
bandwidthKbps: 5000,
|
|
179
|
+
latencyMs: 600,
|
|
180
|
+
jitterMs: 50,
|
|
181
|
+
packetLossPercent: 1.0,
|
|
182
|
+
};
|
|
183
|
+
/** Congested WiFi: ~2 Mbps, 50ms latency, high jitter and packet loss */
|
|
184
|
+
export const NETWORK_WIFI_CONGESTED = {
|
|
185
|
+
bandwidthKbps: 2000,
|
|
186
|
+
latencyMs: 50,
|
|
187
|
+
jitterMs: 40,
|
|
188
|
+
packetLossPercent: 3.0,
|
|
189
|
+
};
|
|
190
|
+
/** Very bad network: ~100 Kbps, 500ms latency, extreme jitter and packet loss */
|
|
191
|
+
export const NETWORK_VERY_BAD = {
|
|
192
|
+
bandwidthKbps: 100,
|
|
193
|
+
latencyMs: 500,
|
|
194
|
+
jitterMs: 200,
|
|
195
|
+
packetLossPercent: 10.0,
|
|
196
|
+
};
|
|
197
|
+
/** Offline: 100% packet loss — drops all packets to simulate no connectivity */
|
|
198
|
+
export const NETWORK_OFFLINE = {
|
|
199
|
+
packetLossPercent: 100,
|
|
200
|
+
};
|
|
201
|
+
export const NetworkConditionStatusSchema = z.object({
|
|
202
|
+
enabled: z.boolean(),
|
|
203
|
+
config: NetworkConditionConfigSchema.optional(),
|
|
204
|
+
interface: z.string().optional(),
|
|
205
|
+
});
|
|
206
|
+
// ============================================================================
|
|
207
|
+
// Internal helpers
|
|
208
|
+
// ============================================================================
|
|
209
|
+
/**
|
|
210
|
+
* Resolve tunnel config by reading file contents for VPN configs.
|
|
211
|
+
* The plugin runs in a container and needs the file content, not the path.
|
|
212
|
+
*/
|
|
213
|
+
async function resolveTunnelConfig(tunnel) {
|
|
214
|
+
switch (tunnel.type) {
|
|
215
|
+
case "direct":
|
|
216
|
+
return { type: "direct" };
|
|
217
|
+
case "http-proxy":
|
|
218
|
+
return {
|
|
219
|
+
type: "http-proxy",
|
|
220
|
+
host: tunnel.host,
|
|
221
|
+
port: tunnel.port,
|
|
222
|
+
username: tunnel.username,
|
|
223
|
+
password: tunnel.password,
|
|
224
|
+
};
|
|
225
|
+
case "wireguard": {
|
|
226
|
+
const configContent = await readFile(tunnel.configPath, "utf-8");
|
|
227
|
+
return { type: "wireguard", configContent };
|
|
228
|
+
}
|
|
229
|
+
case "openvpn": {
|
|
230
|
+
const configContent = await readFile(tunnel.configPath, "utf-8");
|
|
231
|
+
return { type: "openvpn", configContent };
|
|
232
|
+
}
|
|
233
|
+
case "relay":
|
|
234
|
+
return {
|
|
235
|
+
type: "relay",
|
|
236
|
+
host: tunnel.host,
|
|
237
|
+
port: tunnel.port,
|
|
238
|
+
username: tunnel.username,
|
|
239
|
+
password: tunnel.password,
|
|
240
|
+
dialer: tunnel.dialer,
|
|
241
|
+
secure: tunnel.secure,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function getAppiumBaseUrl() {
|
|
246
|
+
// Platform runner uses APPIUM_URL; local/E2E tests use APPIUM_HOST/APPIUM_PORT
|
|
247
|
+
if (process.env.APPIUM_URL) {
|
|
248
|
+
return process.env.APPIUM_URL;
|
|
249
|
+
}
|
|
250
|
+
const host = process.env.APPIUM_HOST || "127.0.0.1";
|
|
251
|
+
const port = process.env.APPIUM_PORT || "4723";
|
|
252
|
+
return `http://${host}:${port}`;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Make a request to the Appium server's sessionless endpoint.
|
|
256
|
+
* Unwraps the W3C WebDriver `{ value: <result> }` envelope.
|
|
257
|
+
*/
|
|
258
|
+
async function appiumFetch(method, path, body) {
|
|
259
|
+
const url = `${getAppiumBaseUrl()}${path}`;
|
|
260
|
+
const headers = { "Content-Type": "application/json" };
|
|
261
|
+
if (process.env.DEVICE_JWT) {
|
|
262
|
+
headers["Authorization"] = `Bearer ${process.env.DEVICE_JWT}`;
|
|
263
|
+
}
|
|
264
|
+
const init = {
|
|
265
|
+
method,
|
|
266
|
+
headers,
|
|
267
|
+
};
|
|
268
|
+
if (body !== undefined) {
|
|
269
|
+
init.body = JSON.stringify(body);
|
|
270
|
+
}
|
|
271
|
+
const response = await fetch(url, init);
|
|
272
|
+
const json = (await response.json());
|
|
273
|
+
if (!response.ok) {
|
|
274
|
+
const errorDetail = json.value &&
|
|
275
|
+
typeof json.value === "object" &&
|
|
276
|
+
"error" in json.value
|
|
277
|
+
? json.value.error
|
|
278
|
+
: JSON.stringify(json.value);
|
|
279
|
+
throw new Error(`Appium ${method} ${path} failed (${response.status}): ${errorDetail}`);
|
|
280
|
+
}
|
|
281
|
+
return json.value;
|
|
282
|
+
}
|
|
283
|
+
// ============================================================================
|
|
284
|
+
// Status Function
|
|
285
|
+
// ============================================================================
|
|
286
|
+
/**
|
|
287
|
+
* Get the current network routing status via the Appium server's sessionless endpoint.
|
|
288
|
+
*
|
|
289
|
+
* Appium URL is resolved from APPIUM_HOST / APPIUM_PORT env vars (default 127.0.0.1:4723).
|
|
290
|
+
*
|
|
291
|
+
* @returns Combined network status
|
|
292
|
+
*/
|
|
293
|
+
export async function getNetworkStatus() {
|
|
294
|
+
const result = await appiumFetch("GET", "/qawolf/network/status");
|
|
295
|
+
return NetworkStatusSchema.parse(result);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Subscribe to real-time network entries streamed via SSE from the
|
|
299
|
+
* Appium plugin. Requires `routeTraffic()` to have been called first
|
|
300
|
+
* with `inspect: true`.
|
|
301
|
+
*
|
|
302
|
+
* Each call opens its own SSE connection to the plugin; closing the
|
|
303
|
+
* subscription tears it down. No shared state.
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* const logs = ios.subscribeNetworkLogs();
|
|
308
|
+
* logs.on((entry) => {
|
|
309
|
+
* if (entry.http) console.log(`${entry.http.method} ${entry.http.uri} → ${entry.http.statusCode}`);
|
|
310
|
+
* if (entry.dns) console.log(`DNS ${entry.dns.name} → ${entry.dns.answer}`);
|
|
311
|
+
* });
|
|
312
|
+
*
|
|
313
|
+
* // ... run tests ...
|
|
314
|
+
*
|
|
315
|
+
* logs.close();
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
export function subscribeNetworkLogs() {
|
|
319
|
+
const handlers = new Set();
|
|
320
|
+
const abortController = new AbortController();
|
|
321
|
+
const sseUrl = `${getAppiumBaseUrl()}/qawolf/network/logs/stream`;
|
|
322
|
+
// Start reading the SSE stream in the background
|
|
323
|
+
void (async () => {
|
|
324
|
+
try {
|
|
325
|
+
const headers = { Accept: "text/event-stream" };
|
|
326
|
+
if (process.env.DEVICE_JWT) {
|
|
327
|
+
headers["Authorization"] = `Bearer ${process.env.DEVICE_JWT}`;
|
|
328
|
+
}
|
|
329
|
+
const response = await fetch(sseUrl, {
|
|
330
|
+
headers,
|
|
331
|
+
signal: abortController.signal,
|
|
332
|
+
});
|
|
333
|
+
if (!response.ok || !response.body)
|
|
334
|
+
return;
|
|
335
|
+
const reader = response.body.getReader();
|
|
336
|
+
const decoder = new TextDecoder();
|
|
337
|
+
let buffer = "";
|
|
338
|
+
while (true) {
|
|
339
|
+
const { done, value } = await reader.read();
|
|
340
|
+
if (done)
|
|
341
|
+
break;
|
|
342
|
+
buffer += decoder.decode(value, { stream: true });
|
|
343
|
+
const lines = buffer.split("\n");
|
|
344
|
+
buffer = lines.pop() ?? "";
|
|
345
|
+
for (const line of lines) {
|
|
346
|
+
if (!line.startsWith("data: "))
|
|
347
|
+
continue;
|
|
348
|
+
try {
|
|
349
|
+
const entry = JSON.parse(line.slice(6));
|
|
350
|
+
for (const handler of handlers) {
|
|
351
|
+
handler(entry);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
// not valid JSON — skip
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
catch (err) {
|
|
361
|
+
if (err instanceof Error && err.name === "AbortError")
|
|
362
|
+
return;
|
|
363
|
+
// SSE connection error — silently stop
|
|
364
|
+
}
|
|
365
|
+
})();
|
|
366
|
+
return {
|
|
367
|
+
on(handler) {
|
|
368
|
+
handlers.add(handler);
|
|
369
|
+
},
|
|
370
|
+
close() {
|
|
371
|
+
handlers.clear();
|
|
372
|
+
abortController.abort();
|
|
373
|
+
},
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
// ============================================================================
|
|
377
|
+
export async function routeTraffic(config) {
|
|
378
|
+
RouteTrafficConfigSchema.parse(config);
|
|
379
|
+
const tunnel = await resolveTunnelConfig(config.tunnel);
|
|
380
|
+
await appiumFetch("POST", "/qawolf/network/route", {
|
|
381
|
+
apps: config.apps,
|
|
382
|
+
domains: config.domains,
|
|
383
|
+
tunnel,
|
|
384
|
+
socksHost: config.socksHost,
|
|
385
|
+
socksPort: config.socksPort,
|
|
386
|
+
inspect: config.inspect,
|
|
387
|
+
});
|
|
388
|
+
return async () => {
|
|
389
|
+
await appiumFetch("DELETE", "/qawolf/network/route");
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
// ============================================================================
|
|
393
|
+
// Network Condition Simulation
|
|
394
|
+
// ============================================================================
|
|
395
|
+
/**
|
|
396
|
+
* Simulate a network condition (bandwidth limit, latency, jitter, packet loss)
|
|
397
|
+
* on traffic flowing through the gateway.
|
|
398
|
+
*
|
|
399
|
+
* Returns a cleanup function that clears the condition.
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* ```typescript
|
|
403
|
+
* // Use a built-in preset
|
|
404
|
+
* const cleanup = await ios.simulateNetworkCondition(ios.NETWORK_3G);
|
|
405
|
+
* await cleanup();
|
|
406
|
+
*
|
|
407
|
+
* // Custom config
|
|
408
|
+
* const cleanup = await ios.simulateNetworkCondition({ bandwidthKbps: 500, latencyMs: 200 });
|
|
409
|
+
* await cleanup();
|
|
410
|
+
* ```
|
|
411
|
+
*/
|
|
412
|
+
export async function simulateNetworkCondition(config) {
|
|
413
|
+
NetworkConditionConfigSchema.parse(config);
|
|
414
|
+
// Network simulation requires routeTraffic() to be called first so that
|
|
415
|
+
// app traffic flows through the gateway where shaping is applied.
|
|
416
|
+
const status = await getNetworkStatus();
|
|
417
|
+
if (!status.vpnApp.installed) {
|
|
418
|
+
throw new Error("simulateNetworkCondition requires routeTraffic() to be called first. " +
|
|
419
|
+
"Network shaping is applied at the gateway, so app traffic must be routed through it.");
|
|
420
|
+
}
|
|
421
|
+
await appiumFetch("POST", "/qawolf/network/condition", { config });
|
|
422
|
+
return async () => {
|
|
423
|
+
await appiumFetch("DELETE", "/qawolf/network/condition");
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Get the current network condition status.
|
|
428
|
+
*/
|
|
429
|
+
export async function getNetworkCondition() {
|
|
430
|
+
const result = await appiumFetch("GET", "/qawolf/network/condition");
|
|
431
|
+
return NetworkConditionStatusSchema.parse(result);
|
|
432
|
+
}
|
|
433
|
+
//# sourceMappingURL=gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @qawolf/run-globals-ios
|
|
3
|
+
*
|
|
4
|
+
* iOS testing utilities for QA Wolf - audio recording and photos management.
|
|
5
|
+
* This package provides standalone functions for interacting with iOS devices
|
|
6
|
+
* through WebDriverIO, following a flat API similar to Android run-globals.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
*
|
|
11
|
+
* // Speaker audio recording (captures device audio output)
|
|
12
|
+
* const session = await ios.startSpeakerRecording(driver);
|
|
13
|
+
* await new Promise(resolve => setTimeout(resolve, 5000));
|
|
14
|
+
* const file = await ios.stopSpeakerRecording(driver, session.id);
|
|
15
|
+
* const audioBuffer = await ios.downloadSpeakerRecording(driver, file.filename);
|
|
16
|
+
*
|
|
17
|
+
* // Photo management
|
|
18
|
+
* await ios.savePhoto(driver, '/path/to/photo.jpg');
|
|
19
|
+
* const photos = await ios.listPhotos(driver);
|
|
20
|
+
* await ios.deleteAllPhotos(driver);
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @packageDocumentation
|
|
24
|
+
*/
|
|
25
|
+
export { startSpeakerRecording, stopSpeakerRecording, downloadSpeakerRecording, calculateAudioFingerprint, } from "./audio.js";
|
|
26
|
+
export type { SpeakerRecordingSession, SpeakerRecordingFile, AudioFingerprint } from "./audio.js";
|
|
27
|
+
export { savePhoto, listPhotos, deleteAllPhotos } from "./photo.js";
|
|
28
|
+
export type { PhotoAsset, SavePhotoResult, ListPhotosResult, DeletePhotosResult } from "./photo.js";
|
|
29
|
+
export { installConfigurationProfile } from "./configuration-profile.js";
|
|
30
|
+
export type { ConfigurationProfileOptions } from "./configuration-profile.js";
|
|
31
|
+
export { routeTraffic, getNetworkStatus, subscribeNetworkLogs, simulateNetworkCondition, getNetworkCondition, NETWORK_2G_EDGE, NETWORK_3G, NETWORK_4G_LTE, NETWORK_5G, NETWORK_SATELLITE, NETWORK_WIFI_CONGESTED, NETWORK_VERY_BAD, NETWORK_OFFLINE, NetworkConditionConfigSchema, NetworkConditionStatusSchema, } from "./gateway.js";
|
|
32
|
+
export type { RouteType, TunnelStatus, TunnelState, TunnelStatusMap, NetworkStatus, NetworkLogSubscription, HttpProxyTunnel, WireGuardTunnel, OpenVPNTunnel, TunnelConfig, RouteTrafficConfig, NetworkConditionConfig, NetworkConditionStatus, RecordedEntry, } from "./gateway.js";
|
|
33
|
+
export { injectBarcode } from "./barcode.js";
|
|
34
|
+
export type { BarcodeConfig } from "./barcode.js";
|
|
35
|
+
export { injectCamera, injectAudio } from "./media.js";
|
|
36
|
+
export type { CameraSource, AudioSource } from "./media.js";
|
|
37
|
+
export { injectBeacon } from "./beacon.js";
|
|
38
|
+
export type { BeaconConfig } from "./beacon.js";
|
|
39
|
+
export { setWebViewDebugging } from "./webview.js";
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGlG,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGpE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGpG,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAGzE,YAAY,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAG9E,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,cAAc,CAAC;AAGtB,YAAY,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,eAAe,EACf,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,aAAa,GACd,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @qawolf/run-globals-ios
|
|
3
|
+
*
|
|
4
|
+
* iOS testing utilities for QA Wolf - audio recording and photos management.
|
|
5
|
+
* This package provides standalone functions for interacting with iOS devices
|
|
6
|
+
* through WebDriverIO, following a flat API similar to Android run-globals.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
*
|
|
11
|
+
* // Speaker audio recording (captures device audio output)
|
|
12
|
+
* const session = await ios.startSpeakerRecording(driver);
|
|
13
|
+
* await new Promise(resolve => setTimeout(resolve, 5000));
|
|
14
|
+
* const file = await ios.stopSpeakerRecording(driver, session.id);
|
|
15
|
+
* const audioBuffer = await ios.downloadSpeakerRecording(driver, file.filename);
|
|
16
|
+
*
|
|
17
|
+
* // Photo management
|
|
18
|
+
* await ios.savePhoto(driver, '/path/to/photo.jpg');
|
|
19
|
+
* const photos = await ios.listPhotos(driver);
|
|
20
|
+
* await ios.deleteAllPhotos(driver);
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @packageDocumentation
|
|
24
|
+
*/
|
|
25
|
+
// Speaker audio recording functions (records device audio output)
|
|
26
|
+
export { startSpeakerRecording, stopSpeakerRecording, downloadSpeakerRecording, calculateAudioFingerprint, } from "./audio.js";
|
|
27
|
+
// Photo functions
|
|
28
|
+
export { savePhoto, listPhotos, deleteAllPhotos } from "./photo.js";
|
|
29
|
+
// Configuration profile functions
|
|
30
|
+
export { installConfigurationProfile } from "./configuration-profile.js";
|
|
31
|
+
// Gateway routing functions
|
|
32
|
+
export { routeTraffic, getNetworkStatus, subscribeNetworkLogs, simulateNetworkCondition, getNetworkCondition, NETWORK_2G_EDGE, NETWORK_3G, NETWORK_4G_LTE, NETWORK_5G, NETWORK_SATELLITE, NETWORK_WIFI_CONGESTED, NETWORK_VERY_BAD, NETWORK_OFFLINE, NetworkConditionConfigSchema, NetworkConditionStatusSchema, } from "./gateway.js";
|
|
33
|
+
// Code injection functions
|
|
34
|
+
export { injectBarcode } from "./barcode.js";
|
|
35
|
+
export { injectCamera, injectAudio } from "./media.js";
|
|
36
|
+
export { injectBeacon } from "./beacon.js";
|
|
37
|
+
export { setWebViewDebugging } from "./webview.js";
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,kEAAkE;AAClE,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAKpB,kBAAkB;AAClB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKpE,kCAAkC;AAClC,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAKzE,4BAA4B;AAC5B,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,cAAc,CAAC;AAoBtB,2BAA2B;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Browser } from "webdriverio";
|
|
2
|
+
export declare function isRemoteSource(data: string): boolean;
|
|
3
|
+
export declare function inferMediaType(filePath: string): "image" | "video";
|
|
4
|
+
export declare function qawolfPath(bundleId: string, filename: string): string;
|
|
5
|
+
export declare function pushJsonConfig(driver: Browser, bundleId: string, filename: string, config: unknown): Promise<() => Promise<void>>;
|
|
6
|
+
export declare function pushRawContent(driver: Browser, bundleId: string, filename: string, content: string): Promise<() => Promise<void>>;
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a media `data` field to a reference the injection dylib can load.
|
|
9
|
+
*
|
|
10
|
+
* Remote sources (http/https/data URIs) are returned as-is. Local file paths
|
|
11
|
+
* are read, pushed to the device under `Documents/.qawolf/`, and referenced
|
|
12
|
+
* by filename. The returned cleanup removes any pushed file.
|
|
13
|
+
*/
|
|
14
|
+
export declare function pushLocalOrRemoteMedia(driver: Browser, bundleId: string, data: string): Promise<{
|
|
15
|
+
dataRef: string;
|
|
16
|
+
cleanup: () => Promise<void>;
|
|
17
|
+
}>;
|
|
18
|
+
//# sourceMappingURL=injectionHelpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injectionHelpers.d.ts","sourceRoot":"","sources":["../src/injectionHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAM3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMpD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAGlE;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAY9B;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAW9B;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAoB5D"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
const VIDEO_EXTENSIONS = new Set([".mp4", ".mov", ".m4v", ".avi"]);
|
|
4
|
+
export function isRemoteSource(data) {
|
|
5
|
+
return (data.startsWith("http://") ||
|
|
6
|
+
data.startsWith("https://") ||
|
|
7
|
+
data.startsWith("data:"));
|
|
8
|
+
}
|
|
9
|
+
export function inferMediaType(filePath) {
|
|
10
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
11
|
+
return VIDEO_EXTENSIONS.has(ext) ? "video" : "image";
|
|
12
|
+
}
|
|
13
|
+
export function qawolfPath(bundleId, filename) {
|
|
14
|
+
return `@${bundleId}:Documents/.qawolf/${filename}`;
|
|
15
|
+
}
|
|
16
|
+
export async function pushJsonConfig(driver, bundleId, filename, config) {
|
|
17
|
+
const content = Buffer.from(JSON.stringify(config)).toString("base64");
|
|
18
|
+
const devicePath = qawolfPath(bundleId, filename);
|
|
19
|
+
await driver.pushFile(devicePath, content);
|
|
20
|
+
return async () => {
|
|
21
|
+
try {
|
|
22
|
+
await driver.execute("mobile: deleteFile", { remotePath: devicePath });
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// File may already be consumed by the injection system
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export async function pushRawContent(driver, bundleId, filename, content) {
|
|
30
|
+
const devicePath = qawolfPath(bundleId, filename);
|
|
31
|
+
await driver.pushFile(devicePath, Buffer.from(content).toString("base64"));
|
|
32
|
+
return async () => {
|
|
33
|
+
try {
|
|
34
|
+
await driver.execute("mobile: deleteFile", { remotePath: devicePath });
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Ignore cleanup errors
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a media `data` field to a reference the injection dylib can load.
|
|
43
|
+
*
|
|
44
|
+
* Remote sources (http/https/data URIs) are returned as-is. Local file paths
|
|
45
|
+
* are read, pushed to the device under `Documents/.qawolf/`, and referenced
|
|
46
|
+
* by filename. The returned cleanup removes any pushed file.
|
|
47
|
+
*/
|
|
48
|
+
export async function pushLocalOrRemoteMedia(driver, bundleId, data) {
|
|
49
|
+
if (isRemoteSource(data)) {
|
|
50
|
+
return { dataRef: data, cleanup: async () => { } };
|
|
51
|
+
}
|
|
52
|
+
const fileBuffer = fs.readFileSync(data);
|
|
53
|
+
const fileName = path.basename(data);
|
|
54
|
+
const devicePath = qawolfPath(bundleId, fileName);
|
|
55
|
+
await driver.pushFile(devicePath, fileBuffer.toString("base64"));
|
|
56
|
+
return {
|
|
57
|
+
dataRef: fileName,
|
|
58
|
+
cleanup: async () => {
|
|
59
|
+
try {
|
|
60
|
+
await driver.execute("mobile: deleteFile", { remotePath: devicePath });
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Ignore cleanup errors
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=injectionHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injectionHelpers.js","sourceRoot":"","sources":["../src/injectionHelpers.ts"],"names":[],"mappings":"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"}
|