@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.
Files changed (43) hide show
  1. package/README.md +232 -0
  2. package/dist/audio.d.ts +98 -0
  3. package/dist/audio.d.ts.map +1 -0
  4. package/dist/audio.js +145 -0
  5. package/dist/audio.js.map +1 -0
  6. package/dist/barcode.d.ts +58 -0
  7. package/dist/barcode.d.ts.map +1 -0
  8. package/dist/barcode.js +45 -0
  9. package/dist/barcode.js.map +1 -0
  10. package/dist/beacon.d.ts +48 -0
  11. package/dist/beacon.d.ts.map +1 -0
  12. package/dist/beacon.js +49 -0
  13. package/dist/beacon.js.map +1 -0
  14. package/dist/configuration-profile.d.ts +27 -0
  15. package/dist/configuration-profile.d.ts.map +1 -0
  16. package/dist/configuration-profile.js +40 -0
  17. package/dist/configuration-profile.js.map +1 -0
  18. package/dist/gateway.d.ts +443 -0
  19. package/dist/gateway.d.ts.map +1 -0
  20. package/dist/gateway.js +433 -0
  21. package/dist/gateway.js.map +1 -0
  22. package/dist/index.d.ts +40 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +38 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/injectionHelpers.d.ts +18 -0
  27. package/dist/injectionHelpers.d.ts.map +1 -0
  28. package/dist/injectionHelpers.js +68 -0
  29. package/dist/injectionHelpers.js.map +1 -0
  30. package/dist/media.d.ts +79 -0
  31. package/dist/media.d.ts.map +1 -0
  32. package/dist/media.js +82 -0
  33. package/dist/media.js.map +1 -0
  34. package/dist/photo.d.ts +117 -0
  35. package/dist/photo.d.ts.map +1 -0
  36. package/dist/photo.js +143 -0
  37. package/dist/photo.js.map +1 -0
  38. package/dist/typings.d.ts +773 -0
  39. package/dist/webview.d.ts +23 -0
  40. package/dist/webview.d.ts.map +1 -0
  41. package/dist/webview.js +25 -0
  42. package/dist/webview.js.map +1 -0
  43. package/package.json +68 -0
package/README.md ADDED
@@ -0,0 +1,232 @@
1
+ # @qawolf/run-globals-ios
2
+
3
+ iOS testing utilities for QA Wolf - audio recording and photos management.
4
+
5
+ This package provides standalone functions for interacting with iOS devices through WebDriverIO, following the same flat API pattern as `run-globals-android`.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @qawolf/run-globals-ios
11
+ ```
12
+
13
+ ### Peer Dependencies
14
+
15
+ This package requires WebDriverIO as a peer dependency:
16
+
17
+ ```bash
18
+ npm install webdriverio webdriver
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```typescript
24
+ import * as ios from '@qawolf/run-globals-ios';
25
+
26
+ // Speaker audio recording (captures device audio output)
27
+ const session = await ios.startSpeakerRecording(driver);
28
+ console.log(`Recording started with session ID: ${session.id}`);
29
+
30
+ // Wait for some audio to be recorded
31
+ await new Promise(resolve => setTimeout(resolve, 5000));
32
+
33
+ // Stop recording - this also calculates the fingerprint automatically
34
+ const file = await ios.stopSpeakerRecording(driver, session.id);
35
+ console.log(`Recording saved to: ${file.filename}`);
36
+ if (file.fingerprint) {
37
+ console.log(`Fingerprint has ${file.fingerprint.length} values`);
38
+ }
39
+
40
+ // Download the audio file
41
+ const audioBuffer = await ios.downloadSpeakerRecording(driver, file.filename);
42
+ fs.writeFileSync('/tmp/recording.wav', audioBuffer);
43
+
44
+ // Calculate fingerprint for a reference audio file
45
+ const referenceAudio = fs.readFileSync('/tmp/reference.wav');
46
+ const fingerprint = await ios.calculateAudioFingerprint(driver, referenceAudio);
47
+ console.log(`Reference duration: ${fingerprint.duration}s`);
48
+
49
+ // Save a photo from local filesystem to device Photos library
50
+ const result = await ios.savePhoto(driver, '/Users/me/test-photo.jpg');
51
+ if (result.success) {
52
+ console.log('Photo saved to library');
53
+ }
54
+
55
+ // List all photos in the library
56
+ const photoList = await ios.listPhotos(driver);
57
+ console.log(`Found ${photoList.totalCount} photos`);
58
+
59
+ // Clean up - delete all photos (useful for test cleanup)
60
+ await ios.deleteAllPhotos(driver);
61
+ console.log('All photos deleted');
62
+ ```
63
+
64
+ ## API Reference
65
+
66
+ ### Speaker Audio Recording Functions
67
+
68
+ #### `startSpeakerRecording(driver)`
69
+
70
+ Start recording speaker/system audio output on the iOS device.
71
+
72
+ - **Parameters:**
73
+ - `driver: Browser` - WebDriverIO browser instance
74
+ - **Returns:** `Promise<SpeakerRecordingSession>` - Session information with ID
75
+ - **Throws:** Error if recording fails to start
76
+
77
+ #### `stopSpeakerRecording(driver, sessionId)`
78
+
79
+ Stop speaker audio recording and finalize the file. Automatically calculates audio fingerprint.
80
+
81
+ - **Parameters:**
82
+ - `driver: Browser` - WebDriverIO browser instance
83
+ - `sessionId: string` - Session ID from `startSpeakerRecording()`
84
+ - **Returns:** `Promise<SpeakerRecordingFile>` - File information including optional fingerprint
85
+ - **Throws:** Error if session ID is invalid or stop fails
86
+
87
+ #### `downloadSpeakerRecording(driver, filename)`
88
+
89
+ Download a recorded speaker audio file as a Buffer (WAV format).
90
+
91
+ - **Parameters:**
92
+ - `driver: Browser` - WebDriverIO browser instance
93
+ - `filename: string` - Filename from `stopSpeakerRecording()`
94
+ - **Returns:** `Promise<Buffer>` - Audio file contents
95
+ - **Throws:** Error if file doesn't exist
96
+
97
+ #### `calculateAudioFingerprint(driver, audioData)`
98
+
99
+ Calculate audio fingerprint from audio data.
100
+
101
+ - **Parameters:**
102
+ - `driver: Browser` - WebDriverIO browser instance
103
+ - `audioData: Buffer | string` - WAV audio data as Buffer or base64 string
104
+ - **Returns:** `Promise<AudioFingerprint>` - Fingerprint and duration
105
+ - **Throws:** Error if audio data is invalid
106
+
107
+ ### Photo Functions
108
+
109
+ #### `savePhoto(driver, filePath)`
110
+
111
+ Save a file from the filesystem to the device Photos library. Handles the complete workflow including file transfer and cleanup.
112
+
113
+ - **Parameters:**
114
+ - `driver: Browser` - WebDriverIO browser instance
115
+ - `filePath: string` - Absolute path to file on the filesystem
116
+ - **Returns:** `Promise<SavePhotoResult>` - Success status and optional message
117
+ - **Throws:** Error if file doesn't exist or save fails
118
+
119
+ #### `listPhotos(driver)`
120
+
121
+ List all photos and videos from the Photos library.
122
+
123
+ - **Parameters:**
124
+ - `driver: Browser` - WebDriverIO browser instance
125
+ - **Returns:** `Promise<ListPhotosResult>` - Result with assets array and count
126
+ - **Throws:** Error if listing fails
127
+
128
+ #### `deleteAllPhotos(driver)`
129
+
130
+ Delete all photos and videos from the Photos library. Useful for test cleanup.
131
+
132
+ - **Parameters:**
133
+ - `driver: Browser` - WebDriverIO browser instance
134
+ - **Returns:** `Promise<DeletePhotosResult>` - Result with deleted count
135
+ - **Throws:** Error if deletion fails
136
+
137
+ ## Types
138
+
139
+ ### `SpeakerRecordingSession`
140
+
141
+ ```typescript
142
+ interface SpeakerRecordingSession {
143
+ id: string; // Unique session identifier
144
+ status: string; // Recording status
145
+ }
146
+ ```
147
+
148
+ ### `SpeakerRecordingFile`
149
+
150
+ ```typescript
151
+ interface SpeakerRecordingFile {
152
+ filename: string; // Name of the audio file
153
+ fingerprint?: number[]; // Optional audio fingerprint (array of integers)
154
+ duration?: number; // Optional duration in seconds
155
+ }
156
+ ```
157
+
158
+ ### `AudioFingerprint`
159
+
160
+ ```typescript
161
+ interface AudioFingerprint {
162
+ fingerprint: number[]; // Audio fingerprint (array of integers)
163
+ duration: number; // Duration in seconds
164
+ }
165
+ ```
166
+
167
+ ### `PhotoAsset`
168
+
169
+ ```typescript
170
+ interface PhotoAsset {
171
+ localIdentifier: string;
172
+ mediaType: string;
173
+ mediaSubtype: string;
174
+ creationDate: string;
175
+ modificationDate: string;
176
+ pixelWidth: number;
177
+ pixelHeight: number;
178
+ duration: number;
179
+ isFavorite: boolean;
180
+ isHidden: boolean;
181
+ }
182
+ ```
183
+
184
+ ### `SavePhotoResult`
185
+
186
+ ```typescript
187
+ interface SavePhotoResult {
188
+ success: boolean; // Whether save was successful
189
+ message?: string; // Optional additional information
190
+ }
191
+ ```
192
+
193
+ ### `ListPhotosResult`
194
+
195
+ ```typescript
196
+ interface ListPhotosResult {
197
+ success: boolean;
198
+ assets: PhotoAsset[];
199
+ totalCount: number;
200
+ }
201
+ ```
202
+
203
+ ### `DeletePhotosResult`
204
+
205
+ ```typescript
206
+ interface DeletePhotosResult {
207
+ success: boolean;
208
+ deletedCount: number;
209
+ message?: string;
210
+ }
211
+ ```
212
+
213
+ ## Architecture
214
+
215
+ This package provides a clean, fetch-based HTTP API for iOS testing:
216
+
217
+ - **Flat API**: All functions are exported directly for easy autocomplete
218
+ - **Direct HTTP communication**: Uses native `fetch` API to communicate with Appium/WebDriver server
219
+ - **No driver mutation**: Functions make direct HTTP calls without registering custom commands
220
+ - **Full TypeScript support**: Complete type definitions with comprehensive JSDoc documentation
221
+ - **Explicit dependencies**: Driver is passed explicitly to extract connection information
222
+
223
+ ## Requirements
224
+
225
+ - Node.js ^20
226
+ - WebDriverIO ^8.0.0 or ^9.0.0
227
+ - iOS device or simulator with QA Wolf iOS Agent installed
228
+ - Appium server with ios-agent running
229
+
230
+ ## License
231
+
232
+ MIT
@@ -0,0 +1,98 @@
1
+ import type { Browser } from "webdriverio";
2
+ import { z } from "zod";
3
+ /**
4
+ * Schema for an active speaker recording session
5
+ */
6
+ export declare const SpeakerRecordingSessionSchema: z.ZodObject<{
7
+ id: z.ZodString;
8
+ status: z.ZodString;
9
+ }, z.core.$strip>;
10
+ /**
11
+ * Represents an active speaker recording session
12
+ */
13
+ export type SpeakerRecordingSession = z.input<typeof SpeakerRecordingSessionSchema>;
14
+ /**
15
+ * Schema for a recorded audio file with optional fingerprint data
16
+ */
17
+ export declare const SpeakerRecordingFileSchema: z.ZodObject<{
18
+ filename: z.ZodString;
19
+ fingerprint: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
20
+ duration: z.ZodOptional<z.ZodNumber>;
21
+ }, z.core.$strip>;
22
+ /**
23
+ * Represents a recorded audio file with optional fingerprint data
24
+ */
25
+ export type SpeakerRecordingFile = z.input<typeof SpeakerRecordingFileSchema>;
26
+ /**
27
+ * Schema for the audio fingerprint calculation result
28
+ */
29
+ export declare const AudioFingerprintSchema: z.ZodObject<{
30
+ fingerprint: z.ZodArray<z.ZodNumber>;
31
+ duration: z.ZodNumber;
32
+ }, z.core.$strip>;
33
+ /**
34
+ * Represents the audio fingerprint calculation result
35
+ */
36
+ export type AudioFingerprint = z.input<typeof AudioFingerprintSchema>;
37
+ /**
38
+ * Start audio recording on the iOS device.
39
+ * This creates a new recording session and returns a session identifier
40
+ * that must be used to stop the recording.
41
+ *
42
+ * @param driver - The WebDriverIO browser instance
43
+ * @returns Promise resolving to the audio session information
44
+ * @example
45
+ * ```typescript
46
+ * const session = await ios.startSpeakerRecording(driver);
47
+ * console.log(`Recording started with session ID: ${session.id}`);
48
+ * ```
49
+ */
50
+ export declare function startSpeakerRecording(driver: Browser): Promise<SpeakerRecordingSession>;
51
+ /**
52
+ * Stop audio recording and finalize the audio file.
53
+ * This also calculates the audio fingerprint automatically.
54
+ *
55
+ * @param driver - The WebDriverIO browser instance
56
+ * @param sessionId - The session ID returned from startRecording
57
+ * @returns Promise resolving to the audio file information including fingerprint
58
+ * @example
59
+ * ```typescript
60
+ * const file = await ios.stopSpeakerRecording(driver, session.id);
61
+ * console.log(`Recording saved to: ${file.filename}`);
62
+ * if (file.fingerprint) {
63
+ * console.log(`Fingerprint has ${file.fingerprint.length} values`);
64
+ * }
65
+ * ```
66
+ */
67
+ export declare function stopSpeakerRecording(driver: Browser, sessionId: string): Promise<SpeakerRecordingFile>;
68
+ /**
69
+ * Download a recorded audio file as a Buffer.
70
+ * The audio file is returned in WAV format.
71
+ *
72
+ * @param driver - The WebDriverIO browser instance
73
+ * @param filename - The filename returned from stopRecording
74
+ * @returns Promise resolving to the audio file contents as a Buffer
75
+ * @example
76
+ * ```typescript
77
+ * const audioBuffer = await ios.downloadSpeakerRecording(driver, file.filename);
78
+ * fs.writeFileSync('/tmp/recording.wav', audioBuffer);
79
+ * ```
80
+ */
81
+ export declare function downloadSpeakerRecording(driver: Browser, filename: string): Promise<Buffer>;
82
+ /**
83
+ * Calculate audio fingerprint from audio data.
84
+ * Accepts either a Buffer or base64-encoded string of WAV audio data.
85
+ *
86
+ * @param driver - The WebDriverIO browser instance
87
+ * @param audioData - Audio data as Buffer or base64 string (WAV format)
88
+ * @returns Promise resolving to the fingerprint calculation result
89
+ * @example
90
+ * ```typescript
91
+ * const audioBuffer = fs.readFileSync('/tmp/reference.wav');
92
+ * const fingerprint = await ios.calculateAudioFingerprint(driver, audioBuffer);
93
+ * console.log(`Duration: ${fingerprint.duration}s`);
94
+ * console.log(`Fingerprint: ${fingerprint.fingerprint.slice(0, 10).join(', ')}...`);
95
+ * ```
96
+ */
97
+ export declare function calculateAudioFingerprint(driver: Browser, audioData: Buffer | string): Promise<AudioFingerprint>;
98
+ //# sourceMappingURL=audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,6BAA6B;;;iBAKxC,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF;;GAEG;AACH,eAAO,MAAM,0BAA0B;;;;iBAOrC,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;iBAKjC,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAU7F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,CAAC,CAkB/B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMjG;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,GAAG,MAAM,GACzB,OAAO,CAAC,gBAAgB,CAAC,CAiB3B"}
package/dist/audio.js ADDED
@@ -0,0 +1,145 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Schema for an active speaker recording session
4
+ */
5
+ export const SpeakerRecordingSessionSchema = z.object({
6
+ /** Unique identifier for the recording session */
7
+ id: z.string(),
8
+ /** Current status of the recording session */
9
+ status: z.string(),
10
+ });
11
+ /**
12
+ * Schema for a recorded audio file with optional fingerprint data
13
+ */
14
+ export const SpeakerRecordingFileSchema = z.object({
15
+ /** Name of the recorded audio file */
16
+ filename: z.string(),
17
+ /** Optional audio fingerprint as an array of integers */
18
+ fingerprint: z.array(z.number()).optional(),
19
+ /** Optional duration of the recording in seconds */
20
+ duration: z.number().optional(),
21
+ });
22
+ /**
23
+ * Schema for the audio fingerprint calculation result
24
+ */
25
+ export const AudioFingerprintSchema = z.object({
26
+ /** Audio fingerprint as an array of integers */
27
+ fingerprint: z.array(z.number()),
28
+ /** Duration of the audio in seconds */
29
+ duration: z.number(),
30
+ });
31
+ /**
32
+ * Start audio recording on the iOS device.
33
+ * This creates a new recording session and returns a session identifier
34
+ * that must be used to stop the recording.
35
+ *
36
+ * @param driver - The WebDriverIO browser instance
37
+ * @returns Promise resolving to the audio session information
38
+ * @example
39
+ * ```typescript
40
+ * const session = await ios.startSpeakerRecording(driver);
41
+ * console.log(`Recording started with session ID: ${session.id}`);
42
+ * ```
43
+ */
44
+ export async function startSpeakerRecording(driver) {
45
+ const result = (await driver.execute("qawolf: startAudioRecording", []));
46
+ return {
47
+ id: result.audioSessionId,
48
+ status: result.status,
49
+ };
50
+ }
51
+ /**
52
+ * Stop audio recording and finalize the audio file.
53
+ * This also calculates the audio fingerprint automatically.
54
+ *
55
+ * @param driver - The WebDriverIO browser instance
56
+ * @param sessionId - The session ID returned from startRecording
57
+ * @returns Promise resolving to the audio file information including fingerprint
58
+ * @example
59
+ * ```typescript
60
+ * const file = await ios.stopSpeakerRecording(driver, session.id);
61
+ * console.log(`Recording saved to: ${file.filename}`);
62
+ * if (file.fingerprint) {
63
+ * console.log(`Fingerprint has ${file.fingerprint.length} values`);
64
+ * }
65
+ * ```
66
+ */
67
+ export async function stopSpeakerRecording(driver, sessionId) {
68
+ const result = (await driver.execute("qawolf: stopAudioRecording", [sessionId]));
69
+ // Decode the base64 fingerprint to integer array
70
+ const fingerprint = result.fingerprint && typeof result.fingerprint === "string"
71
+ ? decodeBase64Fingerprint(result.fingerprint)
72
+ : undefined;
73
+ return {
74
+ filename: result.filename,
75
+ fingerprint,
76
+ duration: result.duration,
77
+ };
78
+ }
79
+ /**
80
+ * Download a recorded audio file as a Buffer.
81
+ * The audio file is returned in WAV format.
82
+ *
83
+ * @param driver - The WebDriverIO browser instance
84
+ * @param filename - The filename returned from stopRecording
85
+ * @returns Promise resolving to the audio file contents as a Buffer
86
+ * @example
87
+ * ```typescript
88
+ * const audioBuffer = await ios.downloadSpeakerRecording(driver, file.filename);
89
+ * fs.writeFileSync('/tmp/recording.wav', audioBuffer);
90
+ * ```
91
+ */
92
+ export async function downloadSpeakerRecording(driver, filename) {
93
+ const base64 = (await driver.execute("qawolf: downloadAudioFile", [
94
+ filename,
95
+ ]));
96
+ return Buffer.from(base64, "base64");
97
+ }
98
+ /**
99
+ * Calculate audio fingerprint from audio data.
100
+ * Accepts either a Buffer or base64-encoded string of WAV audio data.
101
+ *
102
+ * @param driver - The WebDriverIO browser instance
103
+ * @param audioData - Audio data as Buffer or base64 string (WAV format)
104
+ * @returns Promise resolving to the fingerprint calculation result
105
+ * @example
106
+ * ```typescript
107
+ * const audioBuffer = fs.readFileSync('/tmp/reference.wav');
108
+ * const fingerprint = await ios.calculateAudioFingerprint(driver, audioBuffer);
109
+ * console.log(`Duration: ${fingerprint.duration}s`);
110
+ * console.log(`Fingerprint: ${fingerprint.fingerprint.slice(0, 10).join(', ')}...`);
111
+ * ```
112
+ */
113
+ export async function calculateAudioFingerprint(driver, audioData) {
114
+ const base64Data = Buffer.isBuffer(audioData) ? audioData.toString("base64") : audioData;
115
+ const result = (await driver.execute("qawolf: calculateAudioFingerprint", [
116
+ { data: base64Data },
117
+ ]));
118
+ // Decode the base64 fingerprint to integer array
119
+ const fingerprint = decodeBase64Fingerprint(result.fingerprint);
120
+ return {
121
+ fingerprint,
122
+ duration: result.duration,
123
+ };
124
+ }
125
+ /**
126
+ * Decode a base64-encoded fingerprint to raw integers.
127
+ * ChromaSwift (the audio fingerprinting library used by the iOS agent)
128
+ * encodes the raw UInt32 array as base64 using little-endian byte order.
129
+ *
130
+ * @param base64Fingerprint - The base64-encoded fingerprint string
131
+ * @returns Array of signed 32-bit integers representing the fingerprint
132
+ */
133
+ function decodeBase64Fingerprint(base64Fingerprint) {
134
+ const buffer = Buffer.from(base64Fingerprint, "base64");
135
+ const fingerprint = [];
136
+ // Read as little-endian 32-bit integers
137
+ for (let i = 0; i < buffer.length; i += 4) {
138
+ if (i + 4 <= buffer.length) {
139
+ const value = buffer.readUInt32LE(i);
140
+ fingerprint.push(value | 0); // Convert to signed 32-bit
141
+ }
142
+ }
143
+ return fingerprint;
144
+ }
145
+ //# sourceMappingURL=audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { Browser } from "webdriverio";
2
+ /**
3
+ * Configuration for a barcode or QR code to inject.
4
+ */
5
+ export interface BarcodeConfig {
6
+ /** AVMetadataObjectType constant. Default: "org.iso.QRCode" */
7
+ type?: string;
8
+ /** The barcode/QR code value to inject */
9
+ value: string;
10
+ /** Normalized bounds (0.0-1.0) for the detected barcode position */
11
+ bounds?: {
12
+ x: number;
13
+ y: number;
14
+ width: number;
15
+ height: number;
16
+ };
17
+ /** Corner points (0.0-1.0) for the detected barcode shape */
18
+ corners?: {
19
+ x: number;
20
+ y: number;
21
+ }[];
22
+ /**
23
+ * Raw binary payload exposed via `AVMetadataMachineReadableCodeObject.rawValue`
24
+ * (iOS 13+). Accepts a Buffer or a base64-encoded string. When omitted, the
25
+ * injector defaults to the UTF-8 encoding of `value`.
26
+ */
27
+ rawValue?: Buffer | string;
28
+ }
29
+ /**
30
+ * Inject a barcode or QR code detection into the app's AVCaptureMetadataOutput.
31
+ *
32
+ * The injected barcode(s) will be delivered to the app's metadata output delegate
33
+ * as if they were scanned by the camera. The config file is auto-consumed by the
34
+ * injection system after delivery.
35
+ *
36
+ * @param driver - The WebDriverIO browser instance
37
+ * @param bundleId - Bundle ID of the target app
38
+ * @param barcodes - Single barcode config or array of configs
39
+ * @returns Cleanup function that removes the injection config
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * // Inject a QR code
44
+ * const cleanup = await ios.injectBarcode(driver, "com.example.app", {
45
+ * value: "https://example.com",
46
+ * });
47
+ *
48
+ * // Inject multiple barcodes
49
+ * const cleanup = await ios.injectBarcode(driver, "com.example.app", [
50
+ * { type: "org.iso.QRCode", value: "https://example.com" },
51
+ * { type: "org.gs1.EAN-13", value: "1234567890123" },
52
+ * ]);
53
+ *
54
+ * await cleanup();
55
+ * ```
56
+ */
57
+ export declare function injectBarcode(driver: Browser, bundleId: string, barcodes: BarcodeConfig | BarcodeConfig[]): Promise<() => Promise<void>>;
58
+ //# sourceMappingURL=barcode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"barcode.d.ts","sourceRoot":"","sources":["../src/barcode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,MAAM,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,6DAA6D;IAC7D,OAAO,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,aAAa,GAAG,aAAa,EAAE,GACxC,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAe9B"}
@@ -0,0 +1,45 @@
1
+ import { pushJsonConfig } from "./injectionHelpers.js";
2
+ /**
3
+ * Inject a barcode or QR code detection into the app's AVCaptureMetadataOutput.
4
+ *
5
+ * The injected barcode(s) will be delivered to the app's metadata output delegate
6
+ * as if they were scanned by the camera. The config file is auto-consumed by the
7
+ * injection system after delivery.
8
+ *
9
+ * @param driver - The WebDriverIO browser instance
10
+ * @param bundleId - Bundle ID of the target app
11
+ * @param barcodes - Single barcode config or array of configs
12
+ * @returns Cleanup function that removes the injection config
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // Inject a QR code
17
+ * const cleanup = await ios.injectBarcode(driver, "com.example.app", {
18
+ * value: "https://example.com",
19
+ * });
20
+ *
21
+ * // Inject multiple barcodes
22
+ * const cleanup = await ios.injectBarcode(driver, "com.example.app", [
23
+ * { type: "org.iso.QRCode", value: "https://example.com" },
24
+ * { type: "org.gs1.EAN-13", value: "1234567890123" },
25
+ * ]);
26
+ *
27
+ * await cleanup();
28
+ * ```
29
+ */
30
+ export async function injectBarcode(driver, bundleId, barcodes) {
31
+ const items = Array.isArray(barcodes) ? barcodes : [barcodes];
32
+ const metadataObjects = items.map((b) => ({
33
+ type: b.type ?? "org.iso.QRCode",
34
+ value: b.value,
35
+ ...(b.bounds && { bounds: b.bounds }),
36
+ ...(b.corners && { corners: b.corners }),
37
+ ...(b.rawValue !== undefined && {
38
+ rawValue: Buffer.isBuffer(b.rawValue) ? b.rawValue.toString("base64") : b.rawValue,
39
+ }),
40
+ }));
41
+ return pushJsonConfig(driver, bundleId, "metadataobject.json", {
42
+ metadataObjects,
43
+ });
44
+ }
45
+ //# sourceMappingURL=barcode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"barcode.js","sourceRoot":"","sources":["../src/barcode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAsBvD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAe,EACf,QAAgB,EAChB,QAAyC;IAEzC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC9D,MAAM,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,gBAAgB;QAChC,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;QACrC,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QACxC,GAAG,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI;YAC9B,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ;SACnF,CAAC;KACH,CAAC,CAAC,CAAC;IAEJ,OAAO,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,qBAAqB,EAAE;QAC7D,eAAe;KAChB,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,48 @@
1
+ import type { Browser } from "webdriverio";
2
+ /**
3
+ * Configuration for iBeacon injection.
4
+ */
5
+ export interface BeaconConfig {
6
+ /** Beacon region UUID */
7
+ uuid: string;
8
+ /**
9
+ * Beacons to simulate in this region. When omitted or empty, only the
10
+ * `.region` file is pushed — the app receives a region-entry callback but
11
+ * no ranging callbacks.
12
+ */
13
+ beacons?: {
14
+ major: number | string;
15
+ minor: number | string;
16
+ }[];
17
+ }
18
+ /**
19
+ * Inject iBeacon detections into the app's CLLocationManager.
20
+ *
21
+ * Always pushes the `{uuid}.region` file, which triggers
22
+ * `locationManager(_:didEnterRegion:)`. When `beacons` is provided, also
23
+ * pushes `{uuid}.beacon` so the app receives
24
+ * `locationManager(_:didRangeBeacons:inRegion:)` callbacks.
25
+ *
26
+ * @param driver - The WebDriverIO browser instance
27
+ * @param bundleId - Bundle ID of the target app
28
+ * @param config - Beacon configuration with UUID and (optional) beacon list
29
+ * @returns Cleanup function that removes the injection config files
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * // Region entry + ranging
34
+ * const cleanup = await ios.injectBeacon(driver, "com.example.app", {
35
+ * uuid: "8613BEAD-5465-4515-8F9C-AEEA717484C9",
36
+ * beacons: [{ major: 1, minor: 7 }],
37
+ * });
38
+ *
39
+ * // Region entry only (no ranging)
40
+ * const cleanup = await ios.injectBeacon(driver, "com.example.app", {
41
+ * uuid: "e62c96fd-014a-454f-9b41-32245d802bb3",
42
+ * });
43
+ *
44
+ * await cleanup();
45
+ * ```
46
+ */
47
+ export declare function injectBeacon(driver: Browser, bundleId: string, config: BeaconConfig): Promise<() => Promise<void>>;
48
+ //# sourceMappingURL=beacon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beacon.d.ts","sourceRoot":"","sources":["../src/beacon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,EAAE,CAAC;CAChE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAwB9B"}