@appium/coresim 1.0.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.
- package/LICENSE +201 -0
- package/README.md +66 -0
- package/binding.gyp +53 -0
- package/lib/src/commands/app.d.ts +88 -0
- package/lib/src/commands/app.d.ts.map +1 -0
- package/lib/src/commands/app.js +133 -0
- package/lib/src/commands/app.js.map +1 -0
- package/lib/src/commands/biometric.d.ts +33 -0
- package/lib/src/commands/biometric.d.ts.map +1 -0
- package/lib/src/commands/biometric.js +44 -0
- package/lib/src/commands/biometric.js.map +1 -0
- package/lib/src/commands/darwin-notification.d.ts +36 -0
- package/lib/src/commands/darwin-notification.d.ts.map +1 -0
- package/lib/src/commands/darwin-notification.js +35 -0
- package/lib/src/commands/darwin-notification.js.map +1 -0
- package/lib/src/commands/interaction.d.ts +48 -0
- package/lib/src/commands/interaction.d.ts.map +1 -0
- package/lib/src/commands/interaction.js +48 -0
- package/lib/src/commands/interaction.js.map +1 -0
- package/lib/src/commands/keychain.d.ts +25 -0
- package/lib/src/commands/keychain.d.ts.map +1 -0
- package/lib/src/commands/keychain.js +52 -0
- package/lib/src/commands/keychain.js.map +1 -0
- package/lib/src/commands/lifecycle.d.ts +101 -0
- package/lib/src/commands/lifecycle.d.ts.map +1 -0
- package/lib/src/commands/lifecycle.js +165 -0
- package/lib/src/commands/lifecycle.js.map +1 -0
- package/lib/src/commands/media.d.ts +28 -0
- package/lib/src/commands/media.d.ts.map +1 -0
- package/lib/src/commands/media.js +27 -0
- package/lib/src/commands/media.js.map +1 -0
- package/lib/src/commands/misc.d.ts +15 -0
- package/lib/src/commands/misc.d.ts.map +1 -0
- package/lib/src/commands/misc.js +12 -0
- package/lib/src/commands/misc.js.map +1 -0
- package/lib/src/commands/pasteboard.d.ts +24 -0
- package/lib/src/commands/pasteboard.d.ts.map +1 -0
- package/lib/src/commands/pasteboard.js +22 -0
- package/lib/src/commands/pasteboard.js.map +1 -0
- package/lib/src/commands/permissions.d.ts +48 -0
- package/lib/src/commands/permissions.d.ts.map +1 -0
- package/lib/src/commands/permissions.js +84 -0
- package/lib/src/commands/permissions.js.map +1 -0
- package/lib/src/commands/process.d.ts +16 -0
- package/lib/src/commands/process.d.ts.map +1 -0
- package/lib/src/commands/process.js +68 -0
- package/lib/src/commands/process.js.map +1 -0
- package/lib/src/commands/screenshot.d.ts +29 -0
- package/lib/src/commands/screenshot.d.ts.map +1 -0
- package/lib/src/commands/screenshot.js +30 -0
- package/lib/src/commands/screenshot.js.map +1 -0
- package/lib/src/commands/spawn.d.ts +48 -0
- package/lib/src/commands/spawn.d.ts.map +1 -0
- package/lib/src/commands/spawn.js +108 -0
- package/lib/src/commands/spawn.js.map +1 -0
- package/lib/src/commands/ui.d.ts +42 -0
- package/lib/src/commands/ui.d.ts.map +1 -0
- package/lib/src/commands/ui.js +44 -0
- package/lib/src/commands/ui.js.map +1 -0
- package/lib/src/commands/webinspector.d.ts +19 -0
- package/lib/src/commands/webinspector.d.ts.map +1 -0
- package/lib/src/commands/webinspector.js +16 -0
- package/lib/src/commands/webinspector.js.map +1 -0
- package/lib/src/errors.d.ts +51 -0
- package/lib/src/errors.d.ts.map +1 -0
- package/lib/src/errors.js +82 -0
- package/lib/src/errors.js.map +1 -0
- package/lib/src/index.d.ts +7 -0
- package/lib/src/index.d.ts.map +1 -0
- package/lib/src/index.js +5 -0
- package/lib/src/index.js.map +1 -0
- package/lib/src/native-simctl.d.ts +62 -0
- package/lib/src/native-simctl.d.ts.map +1 -0
- package/lib/src/native-simctl.js +221 -0
- package/lib/src/native-simctl.js.map +1 -0
- package/lib/src/types.d.ts +267 -0
- package/lib/src/types.d.ts.map +1 -0
- package/lib/src/types.js +29 -0
- package/lib/src/types.js.map +1 -0
- package/lib/src/utils/index.d.ts +3 -0
- package/lib/src/utils/index.d.ts.map +1 -0
- package/lib/src/utils/index.js +3 -0
- package/lib/src/utils/index.js.map +1 -0
- package/lib/src/utils/pkg-root.d.ts +6 -0
- package/lib/src/utils/pkg-root.d.ts.map +1 -0
- package/lib/src/utils/pkg-root.js +12 -0
- package/lib/src/utils/pkg-root.js.map +1 -0
- package/lib/src/utils/run-catching.d.ts +3 -0
- package/lib/src/utils/run-catching.d.ts.map +1 -0
- package/lib/src/utils/run-catching.js +11 -0
- package/lib/src/utils/run-catching.js.map +1 -0
- package/package.json +73 -0
- package/scripts/install.mjs +22 -0
- package/src/commands/app.ts +186 -0
- package/src/commands/biometric.ts +69 -0
- package/src/commands/darwin-notification.ts +51 -0
- package/src/commands/interaction.ts +74 -0
- package/src/commands/keychain.ts +63 -0
- package/src/commands/lifecycle.ts +210 -0
- package/src/commands/media.ts +38 -0
- package/src/commands/misc.ts +20 -0
- package/src/commands/pasteboard.ts +31 -0
- package/src/commands/permissions.ts +122 -0
- package/src/commands/process.ts +80 -0
- package/src/commands/screenshot.ts +46 -0
- package/src/commands/spawn.ts +133 -0
- package/src/commands/ui.ts +61 -0
- package/src/commands/webinspector.ts +23 -0
- package/src/coresim.mm +1066 -0
- package/src/errors.ts +93 -0
- package/src/index.ts +23 -0
- package/src/native/async_bridge.h +164 -0
- package/src/native/nserror_bridge.h +64 -0
- package/src/native/nserror_bridge.mm +30 -0
- package/src/native/objc_runtime.h +45 -0
- package/src/native/objc_runtime.mm +76 -0
- package/src/native/safe_dispatch.h +38 -0
- package/src/native/sim_device.h +143 -0
- package/src/native/sim_device.mm +355 -0
- package/src/native/sim_device_set.h +16 -0
- package/src/native/sim_device_set.mm +40 -0
- package/src/native/sim_pasteboard.h +16 -0
- package/src/native/sim_pasteboard.mm +295 -0
- package/src/native/sim_process.h +13 -0
- package/src/native/sim_process.mm +139 -0
- package/src/native/sim_screenshot.h +28 -0
- package/src/native/sim_screenshot.mm +226 -0
- package/src/native/sim_service_context.h +42 -0
- package/src/native/sim_service_context.mm +92 -0
- package/src/native/tcc_privacy.h +35 -0
- package/src/native/tcc_privacy.mm +256 -0
- package/src/native/value_bridge.h +18 -0
- package/src/native/value_bridge.mm +111 -0
- package/src/native-simctl.ts +288 -0
- package/src/types.ts +302 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/pkg-root.ts +14 -0
- package/src/utils/run-catching.ts +10 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#include "value_bridge.h"
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
|
|
5
|
+
namespace coresim {
|
|
6
|
+
|
|
7
|
+
namespace {
|
|
8
|
+
|
|
9
|
+
// A plain `.c_str()`/`UTF8String` round trip truncates at the first embedded NUL byte, since both
|
|
10
|
+
// treat the buffer as a null-terminated C string — but a JS string (and an NSString) can validly
|
|
11
|
+
// contain U+0000 mid-string. Converting via the actual byte length on both sides preserves it.
|
|
12
|
+
NSString* ToNSString(const std::string& utf8) {
|
|
13
|
+
return [[NSString alloc] initWithBytes:utf8.data() length:utf8.size() encoding:NSUTF8StringEncoding];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
std::string ToStdString(NSString* str) {
|
|
17
|
+
return std::string(str.UTF8String, [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
} // namespace
|
|
21
|
+
|
|
22
|
+
NSObject* JsValueToNSObject(Napi::Env env, Napi::Value value) {
|
|
23
|
+
if (value.IsNull() || value.IsUndefined()) {
|
|
24
|
+
return [NSNull null];
|
|
25
|
+
}
|
|
26
|
+
if (value.IsBoolean()) {
|
|
27
|
+
return @(value.As<Napi::Boolean>().Value());
|
|
28
|
+
}
|
|
29
|
+
if (value.IsNumber()) {
|
|
30
|
+
return @(value.As<Napi::Number>().DoubleValue());
|
|
31
|
+
}
|
|
32
|
+
if (value.IsString()) {
|
|
33
|
+
return ToNSString(value.As<Napi::String>().Utf8Value());
|
|
34
|
+
}
|
|
35
|
+
if (value.IsBuffer()) {
|
|
36
|
+
auto buffer = value.As<Napi::Buffer<uint8_t>>();
|
|
37
|
+
return [NSData dataWithBytes:buffer.Data() length:buffer.Length()];
|
|
38
|
+
}
|
|
39
|
+
if (value.IsArray()) {
|
|
40
|
+
auto array = value.As<Napi::Array>();
|
|
41
|
+
NSMutableArray* result = [NSMutableArray arrayWithCapacity:array.Length()];
|
|
42
|
+
for (uint32_t i = 0; i < array.Length(); i++) {
|
|
43
|
+
[result addObject:JsValueToNSObject(env, array.Get(i))];
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
if (value.IsObject()) {
|
|
48
|
+
auto object = value.As<Napi::Object>();
|
|
49
|
+
Napi::Array keys = object.GetPropertyNames();
|
|
50
|
+
NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:keys.Length()];
|
|
51
|
+
for (uint32_t i = 0; i < keys.Length(); i++) {
|
|
52
|
+
Napi::Value key = keys.Get(i);
|
|
53
|
+
NSString* nsKey = ToNSString(key.As<Napi::String>().Utf8Value());
|
|
54
|
+
result[nsKey] = JsValueToNSObject(env, object.Get(key));
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
return [NSNull null];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Napi::Value NSObjectToJsValue(Napi::Env env, id object) {
|
|
62
|
+
if (object == nil || object == [NSNull null]) {
|
|
63
|
+
return env.Null();
|
|
64
|
+
}
|
|
65
|
+
if ([object isKindOfClass:[NSString class]]) {
|
|
66
|
+
return Napi::String::New(env, ToStdString((NSString*)object));
|
|
67
|
+
}
|
|
68
|
+
if ([object isKindOfClass:[NSNumber class]]) {
|
|
69
|
+
NSNumber* number = (NSNumber*)object;
|
|
70
|
+
if (strcmp(number.objCType, @encode(BOOL)) == 0 || strcmp(number.objCType, @encode(char)) == 0) {
|
|
71
|
+
return Napi::Boolean::New(env, number.boolValue);
|
|
72
|
+
}
|
|
73
|
+
return Napi::Number::New(env, number.doubleValue);
|
|
74
|
+
}
|
|
75
|
+
if ([object isKindOfClass:[NSArray class]]) {
|
|
76
|
+
NSArray* array = (NSArray*)object;
|
|
77
|
+
Napi::Array result = Napi::Array::New(env, array.count);
|
|
78
|
+
for (NSUInteger i = 0; i < array.count; i++) {
|
|
79
|
+
result[static_cast<uint32_t>(i)] = NSObjectToJsValue(env, array[i]);
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
if ([object isKindOfClass:[NSDictionary class]]) {
|
|
84
|
+
NSDictionary* dict = (NSDictionary*)object;
|
|
85
|
+
Napi::Object result = Napi::Object::New(env);
|
|
86
|
+
for (NSString* key in dict) {
|
|
87
|
+
// Napi::Object::Set's named-property overloads forward to napi_set_named_property, which
|
|
88
|
+
// (per the underlying N-API C function's own signature) only ever accepts a null-terminated
|
|
89
|
+
// C string for the key — there's no byte-length variant, so an embedded-NUL key can't go
|
|
90
|
+
// through that path no matter what we do here. Building the key as a proper Napi::String
|
|
91
|
+
// first and setting it via the napi_value-keyed overload (napi_set_property) sidesteps that
|
|
92
|
+
// limitation entirely.
|
|
93
|
+
Napi::String jsKey = Napi::String::New(env, ToStdString(key));
|
|
94
|
+
result.Set(jsKey, NSObjectToJsValue(env, dict[key]));
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
if ([object isKindOfClass:[NSURL class]]) {
|
|
99
|
+
return Napi::String::New(env, ToStdString([(NSURL*)object absoluteString]));
|
|
100
|
+
}
|
|
101
|
+
if ([object isKindOfClass:[NSUUID class]]) {
|
|
102
|
+
return Napi::String::New(env, ToStdString([(NSUUID*)object UUIDString]));
|
|
103
|
+
}
|
|
104
|
+
if ([object isKindOfClass:[NSData class]]) {
|
|
105
|
+
NSData* data = (NSData*)object;
|
|
106
|
+
return Napi::Buffer<uint8_t>::Copy(env, static_cast<const uint8_t*>(data.bytes), data.length);
|
|
107
|
+
}
|
|
108
|
+
return Napi::String::New(env, ToStdString([object description]));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
} // namespace coresim
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import {execFileSync} from 'node:child_process';
|
|
2
|
+
import {createRequire} from 'node:module';
|
|
3
|
+
|
|
4
|
+
import {util} from '@appium/support';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
appInfo,
|
|
8
|
+
getAppContainer,
|
|
9
|
+
installApp,
|
|
10
|
+
installedApps,
|
|
11
|
+
isAppInstalled,
|
|
12
|
+
launchApp,
|
|
13
|
+
removeApp,
|
|
14
|
+
terminateApp,
|
|
15
|
+
} from './commands/app.js';
|
|
16
|
+
import {enrollBiometric, isBiometricEnrolled, sendBiometricMatch} from './commands/biometric.js';
|
|
17
|
+
import {
|
|
18
|
+
getDarwinNotificationState,
|
|
19
|
+
postDarwinNotification,
|
|
20
|
+
setDarwinNotificationState,
|
|
21
|
+
} from './commands/darwin-notification.js';
|
|
22
|
+
import {clearLocation, getEnv, openUrl, pushNotification, setLocation} from './commands/interaction.js';
|
|
23
|
+
import {addCertificate, addRootCertificate, resetKeychain} from './commands/keychain.js';
|
|
24
|
+
import {
|
|
25
|
+
bootDevice,
|
|
26
|
+
createDevice,
|
|
27
|
+
deleteDevice,
|
|
28
|
+
eraseDevice,
|
|
29
|
+
getBootStatus,
|
|
30
|
+
getDevices,
|
|
31
|
+
getSupportedDeviceTypes,
|
|
32
|
+
getSupportedRuntimes,
|
|
33
|
+
shutdownAllDevices,
|
|
34
|
+
shutdownDevice,
|
|
35
|
+
waitForBoot,
|
|
36
|
+
} from './commands/lifecycle.js';
|
|
37
|
+
import {addMedia, addPhoto, addVideo} from './commands/media.js';
|
|
38
|
+
import {shake} from './commands/misc.js';
|
|
39
|
+
import {getPasteboard, setPasteboard} from './commands/pasteboard.js';
|
|
40
|
+
import {getPermission, grantPermission, resetPermission, revokePermission} from './commands/permissions.js';
|
|
41
|
+
import {listProcesses} from './commands/process.js';
|
|
42
|
+
import {getDisplays, getScreenshot} from './commands/screenshot.js';
|
|
43
|
+
import {spawnProcess} from './commands/spawn.js';
|
|
44
|
+
import {
|
|
45
|
+
getAppearance,
|
|
46
|
+
getContentSize,
|
|
47
|
+
getIncreaseContrast,
|
|
48
|
+
setAppearance,
|
|
49
|
+
setContentSize,
|
|
50
|
+
setIncreaseContrast,
|
|
51
|
+
} from './commands/ui.js';
|
|
52
|
+
import {getWebInspectorSocket} from './commands/webinspector.js';
|
|
53
|
+
// Bare re-imports so `declare module './native-simctl.js'` augmentations in the command modules
|
|
54
|
+
// (which add their methods to NativeSimctl's type) reach downstream consumers' emitted .d.ts
|
|
55
|
+
// import graph — the named imports above alone aren't part of NativeSimctl's emitted type
|
|
56
|
+
// surface, so `tsc` would otherwise drop them from the declaration output.
|
|
57
|
+
import './commands/app.js';
|
|
58
|
+
import './commands/biometric.js';
|
|
59
|
+
import './commands/darwin-notification.js';
|
|
60
|
+
import './commands/interaction.js';
|
|
61
|
+
import './commands/keychain.js';
|
|
62
|
+
import './commands/lifecycle.js';
|
|
63
|
+
import './commands/media.js';
|
|
64
|
+
import './commands/misc.js';
|
|
65
|
+
import './commands/pasteboard.js';
|
|
66
|
+
import './commands/permissions.js';
|
|
67
|
+
import './commands/process.js';
|
|
68
|
+
import './commands/screenshot.js';
|
|
69
|
+
import './commands/spawn.js';
|
|
70
|
+
import './commands/ui.js';
|
|
71
|
+
import './commands/webinspector.js';
|
|
72
|
+
import {NativeSimUnavailableError} from './errors.js';
|
|
73
|
+
import type {
|
|
74
|
+
NativeCoreSimModule,
|
|
75
|
+
NativeDeviceHandle,
|
|
76
|
+
NativeDeviceSetHandle,
|
|
77
|
+
NativeServiceContextHandle,
|
|
78
|
+
} from './types.js';
|
|
79
|
+
import {getPkgRoot, PACKAGE_NAME, runCatchingAsync} from './utils/index.js';
|
|
80
|
+
|
|
81
|
+
const require = createRequire(import.meta.url);
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Drives `CoreSimulator.framework` directly — no `simctl`/`xcrun` subprocess — for the operations
|
|
85
|
+
* `node-simctl`'s `Simctl` class exposes over the CLI. Devices are addressed by UDID; each call
|
|
86
|
+
* re-resolves the native handle from the live device set, so a device deleted by another process
|
|
87
|
+
* surfaces as a normal "not found" error rather than stale state.
|
|
88
|
+
*
|
|
89
|
+
* Every method that can trigger a CoreSimulator dispatch is `async`: the native layer runs the
|
|
90
|
+
* underlying call on a libuv threadpool thread (see coresim.mm/async_bridge.h), so a slow
|
|
91
|
+
* install/erase/create/etc. never blocks Node's event loop.
|
|
92
|
+
*
|
|
93
|
+
* The public command surface (everything except the constructor, `frameworkVersion`, and the
|
|
94
|
+
* `_`-prefixed internal helpers below) lives in `src/commands/*.ts`, grouped by topic and mixed
|
|
95
|
+
* into this class via `Object.assign(NativeSimctl.prototype, ...)` at the bottom of this file —
|
|
96
|
+
* mirroring how `@appium/base-driver`'s `BaseDriver` composes its own command surface from
|
|
97
|
+
* `basedriver/commands/*.ts`. Each command module also declares a `declare module
|
|
98
|
+
* './native-simctl.js'` augmentation so `NativeSimctl`'s emitted type includes methods it doesn't
|
|
99
|
+
* textually define.
|
|
100
|
+
*/
|
|
101
|
+
export class NativeSimctl {
|
|
102
|
+
private cachedServiceContext: Promise<NativeServiceContextHandle> | undefined;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param developerDir — defaults to `xcode-select -p` (the active Xcode's Developer dir).
|
|
106
|
+
* Constructing a NativeSimctl must never throw — the platform check and the native
|
|
107
|
+
* sharedServiceContext call both happen lazily in the `_serviceContext` getter below, so only a
|
|
108
|
+
* method that actually needs the simulator (getDevices(), createDevice(), ...) can raise.
|
|
109
|
+
*/
|
|
110
|
+
constructor(private readonly developerDir?: string) {}
|
|
111
|
+
|
|
112
|
+
/** @returns `CFBundleVersion` of the loaded `CoreSimulator.framework` (e.g. `"1171.6"`). */
|
|
113
|
+
static async frameworkVersion(): Promise<string> {
|
|
114
|
+
return runCatchingAsync(() => loadNative().frameworkVersion());
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @internal Not part of the public API — exposed (not `private`) only so `src/commands/*.ts`
|
|
119
|
+
* mixins can call it. Resolves and memoizes the native `SimServiceContext` on first access —
|
|
120
|
+
* never in the constructor. `loadNative()` must run (and throw its typed platform error) before
|
|
121
|
+
* `defaultDeveloperDir()` ever shells out to `xcode-select`, which doesn't exist off macOS — so
|
|
122
|
+
* the fallback is resolved as an argument to the native call, not eagerly, preserving that
|
|
123
|
+
* evaluation order. Caching the in-flight promise (not just its resolved value) means concurrent
|
|
124
|
+
* callers before the first resolution still only trigger one `sharedServiceContext` call. On
|
|
125
|
+
* rejection the cache is cleared again — a Promise is truthy even once rejected, so leaving a
|
|
126
|
+
* failed one cached would otherwise make every later call reuse that same stale rejection
|
|
127
|
+
* forever instead of retrying once the underlying condition clears.
|
|
128
|
+
*/
|
|
129
|
+
async _serviceContext(): Promise<NativeServiceContextHandle> {
|
|
130
|
+
if (!this.cachedServiceContext) {
|
|
131
|
+
this.cachedServiceContext = runCatchingAsync(() =>
|
|
132
|
+
loadNative().sharedServiceContext(this.developerDir ?? defaultDeveloperDir()),
|
|
133
|
+
).catch((err: unknown) => {
|
|
134
|
+
this.cachedServiceContext = undefined;
|
|
135
|
+
throw err;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return this.cachedServiceContext;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** @internal Not part of the public API — exposed only so `src/commands/*.ts` mixins can call it. */
|
|
142
|
+
async _deviceSet(): Promise<NativeDeviceSetHandle> {
|
|
143
|
+
const context = await this._serviceContext();
|
|
144
|
+
return runCatchingAsync(() => context.defaultDeviceSet());
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** @internal Not part of the public API — exposed only so `src/commands/*.ts` mixins can call it. */
|
|
148
|
+
async _findDevice(udid: string): Promise<NativeDeviceHandle> {
|
|
149
|
+
return runCatchingAsync(async () => {
|
|
150
|
+
const deviceSet = await this._deviceSet();
|
|
151
|
+
const device = (await deviceSet.devices()).find((candidate) => candidate.udid() === udid);
|
|
152
|
+
if (!device) {
|
|
153
|
+
throw new Error(`No simulator device found with udid '${udid}'`);
|
|
154
|
+
}
|
|
155
|
+
return device;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
Object.assign(NativeSimctl.prototype, {
|
|
161
|
+
// lifecycle
|
|
162
|
+
getDevices,
|
|
163
|
+
getSupportedDeviceTypes,
|
|
164
|
+
getSupportedRuntimes,
|
|
165
|
+
createDevice,
|
|
166
|
+
deleteDevice,
|
|
167
|
+
bootDevice,
|
|
168
|
+
getBootStatus,
|
|
169
|
+
waitForBoot,
|
|
170
|
+
shutdownDevice,
|
|
171
|
+
shutdownAllDevices,
|
|
172
|
+
eraseDevice,
|
|
173
|
+
|
|
174
|
+
// app
|
|
175
|
+
installApp,
|
|
176
|
+
removeApp,
|
|
177
|
+
launchApp,
|
|
178
|
+
terminateApp,
|
|
179
|
+
isAppInstalled,
|
|
180
|
+
appInfo,
|
|
181
|
+
installedApps,
|
|
182
|
+
getAppContainer,
|
|
183
|
+
|
|
184
|
+
// media
|
|
185
|
+
addMedia,
|
|
186
|
+
addPhoto,
|
|
187
|
+
addVideo,
|
|
188
|
+
|
|
189
|
+
// biometric
|
|
190
|
+
isBiometricEnrolled,
|
|
191
|
+
enrollBiometric,
|
|
192
|
+
sendBiometricMatch,
|
|
193
|
+
|
|
194
|
+
// misc
|
|
195
|
+
shake,
|
|
196
|
+
|
|
197
|
+
// interaction
|
|
198
|
+
getEnv,
|
|
199
|
+
openUrl,
|
|
200
|
+
setLocation,
|
|
201
|
+
clearLocation,
|
|
202
|
+
pushNotification,
|
|
203
|
+
|
|
204
|
+
// keychain
|
|
205
|
+
addCertificate,
|
|
206
|
+
addRootCertificate,
|
|
207
|
+
resetKeychain,
|
|
208
|
+
|
|
209
|
+
// ui
|
|
210
|
+
getAppearance,
|
|
211
|
+
setAppearance,
|
|
212
|
+
getIncreaseContrast,
|
|
213
|
+
setIncreaseContrast,
|
|
214
|
+
getContentSize,
|
|
215
|
+
setContentSize,
|
|
216
|
+
|
|
217
|
+
// permissions
|
|
218
|
+
grantPermission,
|
|
219
|
+
revokePermission,
|
|
220
|
+
resetPermission,
|
|
221
|
+
getPermission,
|
|
222
|
+
|
|
223
|
+
// process
|
|
224
|
+
listProcesses,
|
|
225
|
+
|
|
226
|
+
// darwin notification
|
|
227
|
+
getDarwinNotificationState,
|
|
228
|
+
setDarwinNotificationState,
|
|
229
|
+
postDarwinNotification,
|
|
230
|
+
|
|
231
|
+
// pasteboard
|
|
232
|
+
getPasteboard,
|
|
233
|
+
setPasteboard,
|
|
234
|
+
|
|
235
|
+
// screenshot
|
|
236
|
+
getScreenshot,
|
|
237
|
+
getDisplays,
|
|
238
|
+
|
|
239
|
+
// webinspector
|
|
240
|
+
getWebInspectorSocket,
|
|
241
|
+
|
|
242
|
+
// spawn
|
|
243
|
+
spawnProcess,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Loaded lazily (not at module import time) so merely depending on/importing @appium/coresim —
|
|
247
|
+
// e.g. for its error classes or types — works on any platform; only actually using it (booting a
|
|
248
|
+
// simulator, etc.) requires macOS, where CoreSimulator.framework exists. `npm install` never
|
|
249
|
+
// attempts to build the addon on other platforms either (see scripts/install.mjs). Any macOS arch
|
|
250
|
+
// works — node-gyp-build falls back to compiling from source on an arch with no matching
|
|
251
|
+
// prebuild (e.g. an Intel Mac, since only darwin-arm64 is prebuilt today). util.memoize only
|
|
252
|
+
// caches a normal return, never a throw (see @appium/support's util.js), so the platform check
|
|
253
|
+
// below re-runs — and re-throws — on every call until it actually succeeds once.
|
|
254
|
+
const loadNative = util.memoize(function loadNative(): NativeCoreSimModule {
|
|
255
|
+
if (process.platform !== 'darwin') {
|
|
256
|
+
throw new NativeSimUnavailableError(
|
|
257
|
+
`${PACKAGE_NAME} requires macOS — CoreSimulator.framework does not exist on ${process.platform}`,
|
|
258
|
+
'platform',
|
|
259
|
+
process.platform,
|
|
260
|
+
'n/a',
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
return require('node-gyp-build')(getPkgRoot()) as NativeCoreSimModule;
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const DEFAULT_DEVELOPER_DIR_TIMEOUT_MS = 15_000;
|
|
267
|
+
|
|
268
|
+
function defaultDeveloperDir(): string {
|
|
269
|
+
try {
|
|
270
|
+
return execFileSync('xcode-select', ['-p'], {
|
|
271
|
+
encoding: 'utf8',
|
|
272
|
+
timeout: DEFAULT_DEVELOPER_DIR_TIMEOUT_MS,
|
|
273
|
+
}).trim();
|
|
274
|
+
} catch (err) {
|
|
275
|
+
// A non-zero exit (e.g. CLT installed but no Xcode selected) already carries a clear stderr
|
|
276
|
+
// message from xcode-select itself; only ENOENT (the binary isn't on PATH at all) and
|
|
277
|
+
// ETIMEDOUT need a friendlier message than Node's raw "spawnSync xcode-select ENOENT/ETIMEDOUT".
|
|
278
|
+
if ((err as NodeJS.ErrnoException)?.code === 'ENOENT') {
|
|
279
|
+
throw new Error('xcode-select not found on PATH — install Xcode or the Xcode Command Line Tools', {
|
|
280
|
+
cause: err,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
if ((err as NodeJS.ErrnoException)?.code === 'ETIMEDOUT') {
|
|
284
|
+
throw new Error(`xcode-select -p did not respond within ${DEFAULT_DEVELOPER_DIR_TIMEOUT_MS}ms`, {cause: err});
|
|
285
|
+
}
|
|
286
|
+
throw err;
|
|
287
|
+
}
|
|
288
|
+
}
|