appium-mac2-driver 1.8.8 → 1.9.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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [1.9.0](https://github.com/appium/appium-mac2-driver/compare/v1.8.9...v1.9.0) (2024-01-08)
2
+
3
+
4
+ ### Features
5
+
6
+ * Add doctor checks ([#266](https://github.com/appium/appium-mac2-driver/issues/266)) ([001597a](https://github.com/appium/appium-mac2-driver/commit/001597a39ad5a1b9a51d7dec5f161d0c6f8b9460))
7
+
8
+ ## [1.8.9](https://github.com/appium/appium-mac2-driver/compare/v1.8.8...v1.8.9) (2023-12-02)
9
+
10
+
11
+ ### Miscellaneous Chores
12
+
13
+ * update publish.js.yml ([#259](https://github.com/appium/appium-mac2-driver/issues/259)) ([c9d5daa](https://github.com/appium/appium-mac2-driver/commit/c9d5daab3579c1f61e3f63dccccfd484b8989bd8))
14
+
1
15
  ## [1.8.8](https://github.com/appium/appium-mac2-driver/compare/v1.8.7...v1.8.8) (2023-11-08)
2
16
 
3
17
 
package/README.md CHANGED
@@ -25,7 +25,13 @@ On top of standard Appium requirements Mac2 driver also expects the following pr
25
25
  - Xcode 13 or later should be installed
26
26
  - `xcode-select` should be pointing to `<full_path_to_xcode_app>/Contents/Developer` developer directory instead of `/Library/Developer/CommandLineTools` to run `xcodebuild` commands
27
27
  - Xcode Helper app should be enabled for Accessibility access. The app itself could be usually found at `/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Agents/Xcode Helper.app`. In order to enable Accessibility access for it simply open the parent folder in Finder: `open /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Agents/` and drag & drop the `Xcode Helper` app to `Security & Privacy -> Privacy -> Accessibility` list of your `System Preferences`. This action must only be done once.
28
- - `testmanagerd` proccess requires UIAutomation authentication since macOS 12. `automationmodetool enable-automationmode-without-authentication` command may help to disable it. This may be particularly useful in CI environments. [Apple forum thread](https://developer.apple.com/forums/thread/693850).
28
+ - `testmanagerd` process requires UIAutomation authentication since macOS 12. `automationmodetool enable-automationmode-without-authentication` command may help to disable it. This may be particularly useful in CI environments. [Apple forum thread](https://developer.apple.com/forums/thread/693850).
29
+
30
+ ### Doctor
31
+
32
+ Since driver version 1.9.0 you can automate the validation for the most of the above
33
+ requirements as well as various optional ones needed by driver extensions by running the
34
+ `appium driver doctor mac2` server command.
29
35
 
30
36
 
31
37
  ## Capabilities
@@ -0,0 +1,19 @@
1
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
2
+ export class OptionalFfmpegCheck {
3
+ FFMPEG_BINARY: string;
4
+ FFMPEG_INSTALL_LINK: string;
5
+ diagnose(): Promise<import("@appium/types").DoctorCheckResult>;
6
+ fix(): Promise<string>;
7
+ hasAutofix(): boolean;
8
+ isOptional(): boolean;
9
+ }
10
+ export const optionalFfmpegCheck: OptionalFfmpegCheck;
11
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
12
+ export class OptionalAutomationModeCheck {
13
+ diagnose(): Promise<import("@appium/types").DoctorCheckResult>;
14
+ fix(): Promise<string>;
15
+ hasAutofix(): boolean;
16
+ isOptional(): boolean;
17
+ }
18
+ export const optionalAutomationModeCheck: OptionalAutomationModeCheck;
19
+ //# sourceMappingURL=optional-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optional-checks.d.ts","sourceRoot":"","sources":["../../../lib/doctor/optional-checks.js"],"names":[],"mappings":"AAMA,wDAAwD;AACxD;IACE,sBAAyB;IACzB,4BAA6D;IAE7D,+DAMC;IAED,uBAKC;IAED,sBAEC;IAED,sBAEC;CACF;AACD,sDAA6D;AAG7D,wDAAwD;AACxD;IACE,+DAWC;IAED,uBAEC;IAED,sBAEC;IAED,sBAEC;CACF;AACD,sEAA6E"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.optionalAutomationModeCheck = exports.OptionalAutomationModeCheck = exports.optionalFfmpegCheck = exports.OptionalFfmpegCheck = void 0;
4
+ /* eslint-disable require-await */
5
+ const utils_1 = require("./utils");
6
+ const support_1 = require("appium/support");
7
+ const teen_process_1 = require("teen_process");
8
+ require("@colors/colors");
9
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
10
+ class OptionalFfmpegCheck {
11
+ constructor() {
12
+ this.FFMPEG_BINARY = 'ffmpeg';
13
+ this.FFMPEG_INSTALL_LINK = 'https://www.ffmpeg.org/download.html';
14
+ }
15
+ async diagnose() {
16
+ const ffmpegPath = await (0, utils_1.resolveExecutablePath)(this.FFMPEG_BINARY);
17
+ return ffmpegPath
18
+ ? support_1.doctor.okOptional(`${this.FFMPEG_BINARY} exists at '${ffmpegPath}'`)
19
+ : support_1.doctor.nokOptional(`${this.FFMPEG_BINARY} cannot be found`);
20
+ }
21
+ async fix() {
22
+ return (`${`${this.FFMPEG_BINARY}`.bold} is used to capture screen recordings. ` +
23
+ `Please read ${this.FFMPEG_INSTALL_LINK}.`);
24
+ }
25
+ hasAutofix() {
26
+ return false;
27
+ }
28
+ isOptional() {
29
+ return true;
30
+ }
31
+ }
32
+ exports.OptionalFfmpegCheck = OptionalFfmpegCheck;
33
+ exports.optionalFfmpegCheck = new OptionalFfmpegCheck();
34
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
35
+ class OptionalAutomationModeCheck {
36
+ async diagnose() {
37
+ let stdout;
38
+ try {
39
+ ({ stdout } = await (0, teen_process_1.exec)('automationmodetool'));
40
+ }
41
+ catch (err) {
42
+ return support_1.doctor.nokOptional(`Cannot run 'automationmodetool': ${err.stderr || err.message}`);
43
+ }
44
+ if (stdout.includes('disabled')) {
45
+ return support_1.doctor.nokOptional(`Automation Mode is disabled`);
46
+ }
47
+ return support_1.doctor.okOptional(`Automation Mode is enabled`);
48
+ }
49
+ async fix() {
50
+ return `Run \`automationmodetool enable-automationmode-without-authentication\` to enable Automation Mode`;
51
+ }
52
+ hasAutofix() {
53
+ return false;
54
+ }
55
+ isOptional() {
56
+ return true;
57
+ }
58
+ }
59
+ exports.OptionalAutomationModeCheck = OptionalAutomationModeCheck;
60
+ exports.optionalAutomationModeCheck = new OptionalAutomationModeCheck();
61
+ //# sourceMappingURL=optional-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optional-checks.js","sourceRoot":"","sources":["../../../lib/doctor/optional-checks.js"],"names":[],"mappings":";;;AAAA,kCAAkC;AAClC,mCAA8C;AAC9C,4CAAsC;AACtC,+CAAkC;AAClC,0BAAwB;AAExB,wDAAwD;AACxD,MAAa,mBAAmB;IAAhC;QACE,kBAAa,GAAG,QAAQ,CAAC;QACzB,wBAAmB,GAAG,sCAAsC,CAAC;IAwB/D,CAAC;IAtBC,KAAK,CAAC,QAAQ;QACZ,MAAM,UAAU,GAAG,MAAM,IAAA,6BAAqB,EAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAEnE,OAAO,UAAU;YACf,CAAC,CAAC,gBAAM,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,aAAa,eAAe,UAAU,GAAG,CAAC;YACtE,CAAC,CAAC,gBAAM,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,aAAa,kBAAkB,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,GAAG;QACP,OAAO,CACL,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,yCAAyC;YACxE,eAAe,IAAI,CAAC,mBAAmB,GAAG,CAC3C,CAAC;IACJ,CAAC;IAED,UAAU;QACR,OAAO,KAAK,CAAC;IACf,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA1BD,kDA0BC;AACY,QAAA,mBAAmB,GAAG,IAAI,mBAAmB,EAAE,CAAC;AAG7D,wDAAwD;AACxD,MAAa,2BAA2B;IACtC,KAAK,CAAC,QAAQ;QACZ,IAAI,MAAM,CAAC;QACX,IAAI;YACF,CAAC,EAAC,MAAM,EAAC,GAAG,MAAM,IAAA,mBAAI,EAAC,oBAAoB,CAAC,CAAC,CAAC;SAC/C;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,gBAAM,CAAC,WAAW,CAAC,oCAAoC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;SAC5F;QACD,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;YAC/B,OAAO,gBAAM,CAAC,WAAW,CAAC,6BAA6B,CAAC,CAAC;SAC1D;QACD,OAAO,gBAAM,CAAC,UAAU,CAAC,4BAA4B,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,GAAG;QACP,OAAO,mGAAmG,CAAC;IAC7G,CAAC;IAED,UAAU;QACR,OAAO,KAAK,CAAC;IACf,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAzBD,kEAyBC;AACY,QAAA,2BAA2B,GAAG,IAAI,2BAA2B,EAAE,CAAC"}
@@ -0,0 +1,19 @@
1
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
2
+ export class XcodeCheck {
3
+ diagnose(): Promise<import("@appium/types").DoctorCheckResult>;
4
+ fix(): Promise<string>;
5
+ hasAutofix(): boolean;
6
+ isOptional(): boolean;
7
+ }
8
+ export const xcodeCheck: XcodeCheck;
9
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
10
+ export class XcodebuildCheck {
11
+ XCODE_VER_PATTERN: RegExp;
12
+ MIN_XCODE_VERSION: number;
13
+ diagnose(): Promise<import("@appium/types").DoctorCheckResult>;
14
+ fix(): Promise<string>;
15
+ hasAutofix(): boolean;
16
+ isOptional(): boolean;
17
+ }
18
+ export const xcodebuildCheck: XcodebuildCheck;
19
+ //# sourceMappingURL=required-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"required-checks.d.ts","sourceRoot":"","sources":["../../../lib/doctor/required-checks.js"],"names":[],"mappings":"AAOA,wDAAwD;AACxD;IACE,+DAOC;IAED,uBAEC;IAED,sBAEC;IAED,sBAEC;CACF;AACD,oCAA2C;AAG3C,wDAAwD;AACxD;IACE,0BAA0C;IAC1C,0BAAuB;IAEvB,+DAoBC;IAED,uBAEC;IAED,sBAEC;IAED,sBAEC;CACF;AACD,8CAAqD"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.xcodebuildCheck = exports.XcodebuildCheck = exports.xcodeCheck = exports.XcodeCheck = void 0;
4
+ /* eslint-disable require-await */
5
+ const support_1 = require("appium/support");
6
+ const teen_process_1 = require("teen_process");
7
+ const appium_xcode_1 = require("appium-xcode");
8
+ require("@colors/colors");
9
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
10
+ class XcodeCheck {
11
+ async diagnose() {
12
+ try {
13
+ const xcodePath = await (0, appium_xcode_1.getPath)();
14
+ return support_1.doctor.ok(`xCode is installed at '${xcodePath}'`);
15
+ }
16
+ catch (err) {
17
+ return support_1.doctor.nok(err.message);
18
+ }
19
+ }
20
+ async fix() {
21
+ return `Manually install ${'Xcode'.bold} and configure the active developer directory path using the xcode-select tool`;
22
+ }
23
+ hasAutofix() {
24
+ return false;
25
+ }
26
+ isOptional() {
27
+ return false;
28
+ }
29
+ }
30
+ exports.XcodeCheck = XcodeCheck;
31
+ exports.xcodeCheck = new XcodeCheck();
32
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
33
+ class XcodebuildCheck {
34
+ constructor() {
35
+ this.XCODE_VER_PATTERN = /^Xcode\s+([\d.]+)$/m;
36
+ this.MIN_XCODE_VERSION = 13;
37
+ }
38
+ async diagnose() {
39
+ let xcodeVerMatch;
40
+ let stdout;
41
+ let stderr;
42
+ try {
43
+ ({ stdout, stderr } = await (0, teen_process_1.exec)('xcodebuild', ['-version']));
44
+ xcodeVerMatch = this.XCODE_VER_PATTERN.exec(stdout);
45
+ }
46
+ catch (err) {
47
+ return support_1.doctor.nok(`Cannot run 'xcodebuild': ${err.stderr || err.message}`);
48
+ }
49
+ if (!xcodeVerMatch) {
50
+ return support_1.doctor.nok(`Cannot determine Xcode version. stdout: ${stdout}; stderr: ${stderr}`);
51
+ }
52
+ const xcodeMajorVer = parseInt(xcodeVerMatch[1], 10);
53
+ if (xcodeMajorVer < this.MIN_XCODE_VERSION) {
54
+ return support_1.doctor.nok(`The actual Xcode version (${xcodeVerMatch[0]}) is older than the expected ` +
55
+ `one (${this.MIN_XCODE_VERSION})`);
56
+ }
57
+ return support_1.doctor.ok(`xcodebuild is installed and has a matching version number ` +
58
+ `(${xcodeVerMatch[1]} >= ${this.MIN_XCODE_VERSION})`);
59
+ }
60
+ async fix() {
61
+ return `Install ${'Xcode'.bold} ${this.MIN_XCODE_VERSION}+ or upgrade the existing setup`;
62
+ }
63
+ hasAutofix() {
64
+ return false;
65
+ }
66
+ isOptional() {
67
+ return false;
68
+ }
69
+ }
70
+ exports.XcodebuildCheck = XcodebuildCheck;
71
+ exports.xcodebuildCheck = new XcodebuildCheck();
72
+ //# sourceMappingURL=required-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"required-checks.js","sourceRoot":"","sources":["../../../lib/doctor/required-checks.js"],"names":[],"mappings":";;;AAAA,kCAAkC;AAClC,4CAAsC;AACtC,+CAAkC;AAClC,+CAAuD;AACvD,0BAAwB;AAGxB,wDAAwD;AACxD,MAAa,UAAU;IACrB,KAAK,CAAC,QAAQ;QACZ,IAAI;YACF,MAAM,SAAS,GAAG,MAAM,IAAA,sBAAY,GAAE,CAAC;YACvC,OAAO,gBAAM,CAAC,EAAE,CAAC,0BAA0B,SAAS,GAAG,CAAC,CAAC;SAC1D;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,gBAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;SAChC;IACH,CAAC;IAED,KAAK,CAAC,GAAG;QACP,OAAO,oBAAoB,OAAO,CAAC,IAAI,gFAAgF,CAAC;IAC1H,CAAC;IAED,UAAU;QACR,OAAO,KAAK,CAAC;IACf,CAAC;IAED,UAAU;QACR,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AArBD,gCAqBC;AACY,QAAA,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;AAG3C,wDAAwD;AACxD,MAAa,eAAe;IAA5B;QACE,sBAAiB,GAAG,qBAAqB,CAAC;QAC1C,sBAAiB,GAAG,EAAE,CAAC;IAmCzB,CAAC;IAjCC,KAAK,CAAC,QAAQ;QACZ,IAAI,aAAa,CAAC;QAClB,IAAI,MAAM,CAAC;QACX,IAAI,MAAM,CAAC;QACX,IAAI;YACF,CAAC,EAAC,MAAM,EAAE,MAAM,EAAC,GAAG,MAAM,IAAA,mBAAI,EAAC,YAAY,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC5D,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SACrD;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,gBAAM,CAAC,GAAG,CAAC,4BAA4B,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;SAC5E;QACD,IAAI,CAAC,aAAa,EAAE;YAClB,OAAO,gBAAM,CAAC,GAAG,CAAC,2CAA2C,MAAM,aAAa,MAAM,EAAE,CAAC,CAAC;SAC3F;QACD,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrD,IAAI,aAAa,GAAG,IAAI,CAAC,iBAAiB,EAAE;YAC1C,OAAO,gBAAM,CAAC,GAAG,CAAC,6BAA6B,aAAa,CAAC,CAAC,CAAC,+BAA+B;gBAC5F,QAAQ,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;SACtC;QACD,OAAO,gBAAM,CAAC,EAAE,CAAC,4DAA4D;YAC3E,IAAI,aAAa,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,GAAG;QACP,OAAO,WAAW,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,iBAAiB,iCAAiC,CAAC;IAC5F,CAAC;IAED,UAAU;QACR,OAAO,KAAK,CAAC;IACf,CAAC;IAED,UAAU;QACR,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AArCD,0CAqCC;AACY,QAAA,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Return an executable path of cmd
3
+ *
4
+ * @param {string} cmd Standard output by command
5
+ * @return {Promise<string?>} The full path of cmd. `null` if the cmd is not found.
6
+ */
7
+ export function resolveExecutablePath(cmd: string): Promise<string | null>;
8
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../lib/doctor/utils.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,2CAHW,MAAM,GACL,QAAQ,MAAM,QAAE,CAU3B"}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveExecutablePath = void 0;
4
+ const support_1 = require("appium/support");
5
+ /**
6
+ * Return an executable path of cmd
7
+ *
8
+ * @param {string} cmd Standard output by command
9
+ * @return {Promise<string?>} The full path of cmd. `null` if the cmd is not found.
10
+ */
11
+ async function resolveExecutablePath(cmd) {
12
+ try {
13
+ const executablePath = await support_1.fs.which(cmd);
14
+ if (executablePath && (await support_1.fs.exists(executablePath))) {
15
+ return executablePath;
16
+ }
17
+ }
18
+ catch (err) { }
19
+ return null;
20
+ }
21
+ exports.resolveExecutablePath = resolveExecutablePath;
22
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../lib/doctor/utils.js"],"names":[],"mappings":";;;AAAA,4CAAkC;AAElC;;;;;GAKG;AACI,KAAK,UAAU,qBAAqB,CAAC,GAAG;IAC7C,IAAI;QACF,MAAM,cAAc,GAAG,MAAM,YAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,cAAc,IAAI,CAAC,MAAM,YAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE;YACvD,OAAO,cAAc,CAAC;SACvB;KACF;IAAC,OAAO,GAAG,EAAE,GAAE;IAChB,OAAO,IAAI,CAAC;AACd,CAAC;AARD,sDAQC"}
@@ -0,0 +1,65 @@
1
+ /* eslint-disable require-await */
2
+ import {resolveExecutablePath} from './utils';
3
+ import {doctor} from 'appium/support';
4
+ import {exec} from 'teen_process';
5
+ import '@colors/colors';
6
+
7
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
8
+ export class OptionalFfmpegCheck {
9
+ FFMPEG_BINARY = 'ffmpeg';
10
+ FFMPEG_INSTALL_LINK = 'https://www.ffmpeg.org/download.html';
11
+
12
+ async diagnose() {
13
+ const ffmpegPath = await resolveExecutablePath(this.FFMPEG_BINARY);
14
+
15
+ return ffmpegPath
16
+ ? doctor.okOptional(`${this.FFMPEG_BINARY} exists at '${ffmpegPath}'`)
17
+ : doctor.nokOptional(`${this.FFMPEG_BINARY} cannot be found`);
18
+ }
19
+
20
+ async fix() {
21
+ return (
22
+ `${`${this.FFMPEG_BINARY}`.bold} is used to capture screen recordings. ` +
23
+ `Please read ${this.FFMPEG_INSTALL_LINK}.`
24
+ );
25
+ }
26
+
27
+ hasAutofix() {
28
+ return false;
29
+ }
30
+
31
+ isOptional() {
32
+ return true;
33
+ }
34
+ }
35
+ export const optionalFfmpegCheck = new OptionalFfmpegCheck();
36
+
37
+
38
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
39
+ export class OptionalAutomationModeCheck {
40
+ async diagnose() {
41
+ let stdout;
42
+ try {
43
+ ({stdout} = await exec('automationmodetool'));
44
+ } catch (err) {
45
+ return doctor.nokOptional(`Cannot run 'automationmodetool': ${err.stderr || err.message}`);
46
+ }
47
+ if (stdout.includes('disabled')) {
48
+ return doctor.nokOptional(`Automation Mode is disabled`);
49
+ }
50
+ return doctor.okOptional(`Automation Mode is enabled`);
51
+ }
52
+
53
+ async fix() {
54
+ return `Run \`automationmodetool enable-automationmode-without-authentication\` to enable Automation Mode`;
55
+ }
56
+
57
+ hasAutofix() {
58
+ return false;
59
+ }
60
+
61
+ isOptional() {
62
+ return true;
63
+ }
64
+ }
65
+ export const optionalAutomationModeCheck = new OptionalAutomationModeCheck();
@@ -0,0 +1,73 @@
1
+ /* eslint-disable require-await */
2
+ import {doctor} from 'appium/support';
3
+ import {exec} from 'teen_process';
4
+ import { getPath as getXcodePath } from 'appium-xcode';
5
+ import '@colors/colors';
6
+
7
+
8
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
9
+ export class XcodeCheck {
10
+ async diagnose() {
11
+ try {
12
+ const xcodePath = await getXcodePath();
13
+ return doctor.ok(`xCode is installed at '${xcodePath}'`);
14
+ } catch (err) {
15
+ return doctor.nok(err.message);
16
+ }
17
+ }
18
+
19
+ async fix() {
20
+ return `Manually install ${'Xcode'.bold} and configure the active developer directory path using the xcode-select tool`;
21
+ }
22
+
23
+ hasAutofix() {
24
+ return false;
25
+ }
26
+
27
+ isOptional() {
28
+ return false;
29
+ }
30
+ }
31
+ export const xcodeCheck = new XcodeCheck();
32
+
33
+
34
+ /** @satisfies {import('@appium/types').IDoctorCheck} */
35
+ export class XcodebuildCheck {
36
+ XCODE_VER_PATTERN = /^Xcode\s+([\d.]+)$/m;
37
+ MIN_XCODE_VERSION = 13;
38
+
39
+ async diagnose() {
40
+ let xcodeVerMatch;
41
+ let stdout;
42
+ let stderr;
43
+ try {
44
+ ({stdout, stderr} = await exec('xcodebuild', ['-version']));
45
+ xcodeVerMatch = this.XCODE_VER_PATTERN.exec(stdout);
46
+ } catch (err) {
47
+ return doctor.nok(`Cannot run 'xcodebuild': ${err.stderr || err.message}`);
48
+ }
49
+ if (!xcodeVerMatch) {
50
+ return doctor.nok(`Cannot determine Xcode version. stdout: ${stdout}; stderr: ${stderr}`);
51
+ }
52
+ const xcodeMajorVer = parseInt(xcodeVerMatch[1], 10);
53
+ if (xcodeMajorVer < this.MIN_XCODE_VERSION) {
54
+ return doctor.nok(`The actual Xcode version (${xcodeVerMatch[0]}) is older than the expected ` +
55
+ `one (${this.MIN_XCODE_VERSION})`);
56
+ }
57
+ return doctor.ok(`xcodebuild is installed and has a matching version number ` +
58
+ `(${xcodeVerMatch[1]} >= ${this.MIN_XCODE_VERSION})`);
59
+ }
60
+
61
+ async fix() {
62
+ return `Install ${'Xcode'.bold} ${this.MIN_XCODE_VERSION}+ or upgrade the existing setup`;
63
+ }
64
+
65
+ hasAutofix() {
66
+ return false;
67
+ }
68
+
69
+ isOptional() {
70
+ return false;
71
+ }
72
+ }
73
+ export const xcodebuildCheck = new XcodebuildCheck();
@@ -0,0 +1,17 @@
1
+ import {fs} from 'appium/support';
2
+
3
+ /**
4
+ * Return an executable path of cmd
5
+ *
6
+ * @param {string} cmd Standard output by command
7
+ * @return {Promise<string?>} The full path of cmd. `null` if the cmd is not found.
8
+ */
9
+ export async function resolveExecutablePath(cmd) {
10
+ try {
11
+ const executablePath = await fs.which(cmd);
12
+ if (executablePath && (await fs.exists(executablePath))) {
13
+ return executablePath;
14
+ }
15
+ } catch (err) {}
16
+ return null;
17
+ }