diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index f28e666..3488807 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -38,5 +38,7 @@ jobs: name: Install dev dependencies - run: npm run lint name: Run linter + - run: npm run format:check + name: Run Prettier check - run: npm run test name: Run unit tests diff --git a/lib/helpers.ts b/lib/helpers.ts index dfd7114..ed34e6e 100644 --- a/lib/helpers.ts +++ b/lib/helpers.ts @@ -1,6 +1,6 @@ import * as semver from 'semver'; -import { spawn } from 'node:child_process'; -import { Readable } from 'node:stream'; +import {spawn} from 'node:child_process'; +import {Readable} from 'node:stream'; export const DEFAULT_EXEC_TIMEOUT = 10 * 60 * 1000; // ms export const SIM_RUNTIME_NAME = 'com.apple.CoreSimulator.SimRuntime.'; @@ -13,7 +13,7 @@ export const SIM_RUNTIME_NAME = 'com.apple.CoreSimulator.SimRuntime.'; * @return The version in 'major.minor' form * @throws {Error} If the version not parseable by the `semver` package */ -export function normalizeVersion (version: string): string { +export function normalizeVersion(version: string): string { const semverVersion = semver.coerce(version); if (!semverVersion) { throw new Error(`Unable to parse version '${version}'`); @@ -24,7 +24,7 @@ export function normalizeVersion (version: string): string { /** * @returns The xcrun binary name */ -export function getXcrunBinary (): string { +export function getXcrunBinary(): string { return process.env.XCRUN_BINARY || 'xcrun'; } @@ -33,7 +33,7 @@ export function getXcrunBinary (): string { * * @returns Promise resolving to UUID string */ -export async function uuidV4 (): Promise { +export async function uuidV4(): Promise { const uuidLib = await import('uuid'); return uuidLib.v4(); } @@ -45,7 +45,7 @@ export async function uuidV4 (): Promise { * @return Promise resolving to parsed JSON object * @throws {Error} If plutil fails to convert the input */ -export async function convertPlistToJson (plistInput: string): Promise { +export async function convertPlistToJson(plistInput: string): Promise { const plutilProcess = spawn('plutil', ['-convert', 'json', '-o', '-', '-']); let jsonOutput = ''; plutilProcess.stdout.on('data', (chunk) => { @@ -71,11 +71,12 @@ export async function convertPlistToJson (plistInput: string): Promise { }); } catch (err) { plutilProcess.kill(9); - throw new Error(`Failed to convert plist to JSON: ${err instanceof Error ? err.message : String(err)}`); + throw new Error( + `Failed to convert plist to JSON: ${err instanceof Error ? err.message : String(err)}`, + ); } finally { plutilProcess.removeAllListeners(); inputStream.removeAllListeners(); } return JSON.parse(jsonOutput); } - diff --git a/lib/logger.ts b/lib/logger.ts index 3bd5f20..3436974 100644 --- a/lib/logger.ts +++ b/lib/logger.ts @@ -2,10 +2,10 @@ import appiumLogger from '@appium/logger'; export const LOG_PREFIX = 'simctl'; -function getLogger () { +function getLogger() { const logger = global._global_npmlog || appiumLogger; if (!logger.debug) { - logger.addLevel('debug', 1000, { fg: 'blue', bg: 'black' }, 'dbug'); + logger.addLevel('debug', 1000, {fg: 'blue', bg: 'black'}, 'dbug'); } return logger; } diff --git a/lib/simctl.ts b/lib/simctl.ts index 3d32e22..418404b 100644 --- a/lib/simctl.ts +++ b/lib/simctl.ts @@ -1,10 +1,8 @@ import _ from 'lodash'; import which from 'which'; -import { log, LOG_PREFIX } from './logger'; -import { - DEFAULT_EXEC_TIMEOUT, getXcrunBinary, -} from './helpers'; -import { exec as tpExec, SubProcess } from 'teen_process'; +import {log, LOG_PREFIX} from './logger'; +import {DEFAULT_EXEC_TIMEOUT, getXcrunBinary} from './helpers'; +import {exec as tpExec, SubProcess} from 'teen_process'; import * as addmediaCommands from './subcommands/addmedia'; import * as appinfoCommands from './subcommands/appinfo'; import * as bootCommands from './subcommands/boot'; @@ -30,9 +28,7 @@ import * as terminateCommands from './subcommands/terminate'; import * as uiCommands from './subcommands/ui'; import * as uninstallCommands from './subcommands/uninstall'; import * as locationCommands from './subcommands/location'; -import type { - XCRun, ExecOpts, SimctlOpts, ExecResult, -} from './types'; +import type {XCRun, ExecOpts, SimctlOpts, ExecResult} from './types'; const SIMCTL_ENV_PREFIX = 'SIMCTL_CHILD_'; @@ -43,27 +39,27 @@ export class Simctl { private _udid: string | null; private _devicesSetPath: string | null; - constructor (opts: SimctlOpts = {}) { - this.xcrun = _.cloneDeep(opts.xcrun ?? { path: null }); + constructor(opts: SimctlOpts = {}) { + this.xcrun = _.cloneDeep(opts.xcrun ?? {path: null}); this.execTimeout = opts.execTimeout ?? DEFAULT_EXEC_TIMEOUT; this.logErrors = opts.logErrors ?? true; this._udid = opts.udid ?? null; this._devicesSetPath = opts.devicesSetPath ?? null; } - set udid (value: string | null) { + set udid(value: string | null) { this._udid = value; } - get udid (): string | null { + get udid(): string | null { return this._udid; } - set devicesSetPath (value: string | null) { + set devicesSetPath(value: string | null) { this._devicesSetPath = value; } - get devicesSetPath (): string | null { + get devicesSetPath(): string | null { return this._devicesSetPath; } @@ -72,10 +68,12 @@ export class Simctl { * @returns The UDID string * @throws {Error} If UDID is not set */ - requireUdid (commandName: string | null = null): string { + requireUdid(commandName: string | null = null): string { if (!this.udid) { - throw new Error(`udid is required to be set for ` + - (commandName ? `the '${commandName}' command` : 'this simctl command')); + throw new Error( + `udid is required to be set for ` + + (commandName ? `the '${commandName}' command` : 'this simctl command'), + ); } return this.udid; } @@ -83,15 +81,17 @@ export class Simctl { /** * @returns Promise resolving to the xcrun binary path */ - async requireXcrun (): Promise { + async requireXcrun(): Promise { const xcrunBinary = getXcrunBinary(); if (!this.xcrun.path) { try { this.xcrun.path = await which(xcrunBinary); } catch { - throw new Error(`${xcrunBinary} tool has not been found in PATH. ` + - `Are Xcode developers tools installed?`); + throw new Error( + `${xcrunBinary} tool has not been found in PATH. ` + + `Are Xcode developers tools installed?`, + ); } } if (!this.xcrun.path) { @@ -110,10 +110,7 @@ export class Simctl { * `SubProcess` instance depending of `opts.asynchronous` value. * @throws {Error} If the simctl subcommand command returns non-zero return code. */ - async exec ( - subcommand: string, - opts?: T - ): Promise> { + async exec(subcommand: string, opts?: T): Promise> { const { args: initialArgs = [], env: initialEnv = {}, @@ -122,20 +119,21 @@ export class Simctl { logErrors = true, architectures, timeout, - } = opts ?? {} as T; + } = opts ?? ({} as T); // run a particular simctl command const args = [ 'simctl', ...(this.devicesSetPath ? ['--set', this.devicesSetPath] : []), subcommand, - ...initialArgs + ...initialArgs, ]; // Prefix all passed in environment variables with 'SIMCTL_CHILD_', simctl // will then pass these to the child (spawned) process. const env = _.defaults( - _.mapKeys(initialEnv, - (value, key) => _.startsWith(key, SIMCTL_ENV_PREFIX) ? key : `${SIMCTL_ENV_PREFIX}${key}`), - process.env + _.mapKeys(initialEnv, (value, key) => + _.startsWith(key, SIMCTL_ENV_PREFIX) ? key : `${SIMCTL_ENV_PREFIX}${key}`, + ), + process.env, ); const execOpts: any = { @@ -150,14 +148,19 @@ export class Simctl { let execArgs: [string, string[], any]; if (architectures?.length) { const archArgs = _.flatMap( - (_.isArray(architectures) ? architectures : [architectures]).map((arch) => ['-arch', arch]) + (_.isArray(architectures) ? architectures : [architectures]).map((arch) => [ + '-arch', + arch, + ]), ); execArgs = ['arch', [...archArgs, xcrun, ...args], execOpts]; } else { execArgs = [xcrun, args, execOpts]; } // We know what we are doing here - the type system can't handle the dynamic nature - return (asynchronous ? new SubProcess(...execArgs) : await tpExec(...execArgs)) as ExecResult; + return ( + asynchronous ? new SubProcess(...execArgs) : await tpExec(...execArgs) + ) as ExecResult; } catch (e: any) { if (!this.logErrors || !logErrors) { // if we don't want to see the errors, just throw and allow the calling @@ -218,4 +221,3 @@ export class Simctl { } export default Simctl; - diff --git a/lib/subcommands/addmedia.ts b/lib/subcommands/addmedia.ts index 403150c..e8f73c4 100644 --- a/lib/subcommands/addmedia.ts +++ b/lib/subcommands/addmedia.ts @@ -1,5 +1,5 @@ -import type { Simctl } from '../simctl'; -import type { TeenProcessExecResult } from 'teen_process'; +import type {Simctl} from '../simctl'; +import type {TeenProcessExecResult} from 'teen_process'; /** * Add the particular media file to Simulator's library. @@ -12,7 +12,10 @@ import type { TeenProcessExecResult } from 'teen_process'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function addMedia (this: Simctl, filePath: string): Promise> { +export async function addMedia( + this: Simctl, + filePath: string, +): Promise> { return await this.exec('addmedia', { args: [this.requireUdid('addmedia'), filePath], }); diff --git a/lib/subcommands/appinfo.ts b/lib/subcommands/appinfo.ts index ca5e76e..f06b9e0 100644 --- a/lib/subcommands/appinfo.ts +++ b/lib/subcommands/appinfo.ts @@ -1,6 +1,6 @@ -import type { Simctl } from '../simctl'; -import type { AppInfo } from '../types'; -import { convertPlistToJson } from '../helpers'; +import type {Simctl} from '../simctl'; +import type {AppInfo} from '../types'; +import {convertPlistToJson} from '../helpers'; import _ from 'lodash'; /** @@ -13,7 +13,7 @@ import _ from 'lodash'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function appInfo (this: Simctl, bundleId: string): Promise { +export async function appInfo(this: Simctl, bundleId: string): Promise { const {stdout} = await this.exec('appinfo', { args: [this.requireUdid('appinfo'), bundleId], }); @@ -26,7 +26,7 @@ export async function appInfo (this: Simctl, bundleId: string): Promise result = await convertPlistToJson(stdout); } catch (err) { throw new Error( - `Cannot retrieve app info for ${bundleId}: ${err instanceof Error ? err.message : String(err)}` + `Cannot retrieve app info for ${bundleId}: ${err instanceof Error ? err.message : String(err)}`, ); } } diff --git a/lib/subcommands/boot.ts b/lib/subcommands/boot.ts index 9a8cb42..eb3cf81 100644 --- a/lib/subcommands/boot.ts +++ b/lib/subcommands/boot.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; -import { log, LOG_PREFIX } from '../logger'; -import type { Simctl } from '../simctl'; +import {log, LOG_PREFIX} from '../logger'; +import type {Simctl} from '../simctl'; /** * Boot the particular Simulator if it is not running. @@ -9,10 +9,10 @@ import type { Simctl } from '../simctl'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function bootDevice (this: Simctl): Promise { +export async function bootDevice(this: Simctl): Promise { try { await this.exec('boot', { - args: [this.requireUdid('boot')] + args: [this.requireUdid('boot')], }); } catch (e: any) { if (_.includes(e.message, 'Unable to boot device in current state: Booted')) { diff --git a/lib/subcommands/bootstatus.ts b/lib/subcommands/bootstatus.ts index 5d7ee50..36ee894 100644 --- a/lib/subcommands/bootstatus.ts +++ b/lib/subcommands/bootstatus.ts @@ -1,9 +1,9 @@ -import { log } from '../logger'; -import { waitForCondition } from 'asyncbox'; +import {log} from '../logger'; +import {waitForCondition} from 'asyncbox'; import _ from 'lodash'; -import type { Simctl } from '../simctl'; -import type { BootMonitorOptions } from '../types'; -import type { SubProcess } from 'teen_process'; +import type {Simctl} from '../simctl'; +import type {BootMonitorOptions} from '../types'; +import type {SubProcess} from 'teen_process'; /** * Start monitoring for boot status of the particular Simulator. @@ -17,92 +17,94 @@ import type { SubProcess } from 'teen_process'; * property is not set. * @throws {Error} If the `udid` instance property is unset */ -export async function startBootMonitor ( +export async function startBootMonitor( this: Simctl, - opts: BootMonitorOptions = {} + opts: BootMonitorOptions = {}, ): Promise { - const { - timeout = 240000, - onWaitingDataMigration, - onWaitingSystemApp, - onFinished, - onError, - shouldPreboot, - } = opts; - const udid = this.requireUdid('bootstatus'); + const { + timeout = 240000, + onWaitingDataMigration, + onWaitingSystemApp, + onFinished, + onError, + shouldPreboot, + } = opts; + const udid = this.requireUdid('bootstatus'); - const status: string[] = []; - let isBootingFinished = false; - let error: Error | null = null; - let timeoutHandler: NodeJS.Timeout | null = null; - const args = [udid]; - if (shouldPreboot) { - args.push('-b'); + const status: string[] = []; + let isBootingFinished = false; + let error: Error | null = null; + let timeoutHandler: NodeJS.Timeout | null = null; + const args = [udid]; + if (shouldPreboot) { + args.push('-b'); + } + const bootMonitor = await this.exec('bootstatus', { + args, + asynchronous: true, + }); + const onStreamLine = (line: string) => { + status.push(line); + if (onWaitingDataMigration && line.includes('Waiting on Data Migration')) { + onWaitingDataMigration(); + } else if (onWaitingSystemApp && line.includes('Waiting on System App')) { + onWaitingSystemApp(); } - const bootMonitor = await this.exec('bootstatus', { - args, - asynchronous: true, - }); - const onStreamLine = (line: string) => { - status.push(line); - if (onWaitingDataMigration && line.includes('Waiting on Data Migration')) { - onWaitingDataMigration(); - } else if (onWaitingSystemApp && line.includes('Waiting on System App')) { - onWaitingSystemApp(); - } - }; - for (const streamName of ['stdout', 'stderr']) { - bootMonitor.on(`line-${streamName}`, onStreamLine); + }; + for (const streamName of ['stdout', 'stderr']) { + bootMonitor.on(`line-${streamName}`, onStreamLine); + } + bootMonitor.once('exit', (code, signal) => { + if (timeoutHandler) { + clearTimeout(timeoutHandler); } - bootMonitor.once('exit', (code, signal) => { - if (timeoutHandler) { - clearTimeout(timeoutHandler); - } - if (code === 0) { - if (onFinished) { - onFinished(); - } - isBootingFinished = true; - } else { - const errMessage = _.isEmpty(status) - ? `The simulator booting process has exited with code ${code} by signal ${signal}` - : status.join('\n'); - error = new Error(errMessage); - if (onError) { - onError(error); - } - } - }); - await bootMonitor.start(0); - const stopMonitor = async () => { - if (bootMonitor.isRunning) { - try { - await bootMonitor.stop(); - } catch (e: any) { - log.warn(e.message); - } + if (code === 0) { + if (onFinished) { + onFinished(); } - }; - const start = process.hrtime(); - if (onFinished) { - timeoutHandler = setTimeout(stopMonitor, timeout); + isBootingFinished = true; } else { + const errMessage = _.isEmpty(status) + ? `The simulator booting process has exited with code ${code} by signal ${signal}` + : status.join('\n'); + error = new Error(errMessage); + if (onError) { + onError(error); + } + } + }); + await bootMonitor.start(0); + const stopMonitor = async () => { + if (bootMonitor.isRunning) { try { - await waitForCondition(() => { + await bootMonitor.stop(); + } catch (e: any) { + log.warn(e.message); + } + } + }; + const start = process.hrtime(); + if (onFinished) { + timeoutHandler = setTimeout(stopMonitor, timeout); + } else { + try { + await waitForCondition( + () => { if (error) { throw error; } return isBootingFinished; - }, {waitMs: timeout, intervalMs: 500}); - } catch { - await stopMonitor(); - const [seconds] = process.hrtime(start); - throw new Error( - `The simulator ${udid} has failed to finish booting after ${seconds}s. ` + - `Original status: ${status.join('\n')}` - ); - } + }, + {waitMs: timeout, intervalMs: 500}, + ); + } catch { + await stopMonitor(); + const [seconds] = process.hrtime(start); + throw new Error( + `The simulator ${udid} has failed to finish booting after ${seconds}s. ` + + `Original status: ${status.join('\n')}`, + ); } - return bootMonitor; + } + return bootMonitor; } - diff --git a/lib/subcommands/create.ts b/lib/subcommands/create.ts index d683aab..7b127ff 100644 --- a/lib/subcommands/create.ts +++ b/lib/subcommands/create.ts @@ -1,9 +1,9 @@ import _ from 'lodash'; -import { log, LOG_PREFIX } from '../logger'; -import { retryInterval } from 'asyncbox'; -import { SIM_RUNTIME_NAME, normalizeVersion } from '../helpers'; -import type { Simctl } from '../simctl'; -import type { SimCreationOpts } from '../types'; +import {log, LOG_PREFIX} from '../logger'; +import {retryInterval} from 'asyncbox'; +import {SIM_RUNTIME_NAME, normalizeVersion} from '../helpers'; +import type {Simctl} from '../simctl'; +import type {SimCreationOpts} from '../types'; const SIM_RUNTIME_NAME_SUFFIX_IOS = 'iOS'; const DEFAULT_CREATE_SIMULATOR_TIMEOUT = 10000; @@ -20,17 +20,14 @@ const DEFAULT_CREATE_SIMULATOR_TIMEOUT = 10000; * @throws {Error} If the corresponding simctl subcommand command * returns non-zero return code. */ -export async function createDevice ( +export async function createDevice( this: Simctl, name: string, deviceTypeId: string, platformVersion: string, - opts: SimCreationOpts = {} + opts: SimCreationOpts = {}, ): Promise { - const { - platform = SIM_RUNTIME_NAME_SUFFIX_IOS, - timeout = DEFAULT_CREATE_SIMULATOR_TIMEOUT - } = opts; + const {platform = SIM_RUNTIME_NAME_SUFFIX_IOS, timeout = DEFAULT_CREATE_SIMULATOR_TIMEOUT} = opts; const runtimeIds: string[] = []; @@ -62,19 +59,23 @@ export async function createDevice ( // add modified versions, since modern Xcodes use this, then the bare // versions, to accomodate older Xcodes runtimeIds.push( - ...(potentialRuntimeIds.map((id) => `${SIM_RUNTIME_NAME}${platform}-${id.replace(/\./g, '-')}`)), - ...potentialRuntimeIds + ...potentialRuntimeIds.map( + (id) => `${SIM_RUNTIME_NAME}${platform}-${id.replace(/\./g, '-')}`, + ), + ...potentialRuntimeIds, ); } // go through the runtime ids and try to create a simulator with each let udid: string | undefined; for (const runtimeId of runtimeIds) { - log.debug(LOG_PREFIX, - `Creating simulator with name '${name}', device type id '${deviceTypeId}' and runtime id '${runtimeId}'`); + log.debug( + LOG_PREFIX, + `Creating simulator with name '${name}', device type id '${deviceTypeId}' and runtime id '${runtimeId}'`, + ); try { const {stdout} = await this.exec('create', { - args: [name, deviceTypeId, runtimeId] + args: [name, deviceTypeId, runtimeId], }); udid = stdout.trim(); break; @@ -84,9 +85,11 @@ export async function createDevice ( } if (!udid) { - throw new Error(`Could not create simulator with name '${name}', device ` + - `type id '${deviceTypeId}', with runtime ids ` + - `${runtimeIds.map((id) => `'${id}'`).join(', ')}`); + throw new Error( + `Could not create simulator with name '${name}', device ` + + `type id '${deviceTypeId}', with runtime ids ` + + `${runtimeIds.map((id) => `'${id}'`).join(', ')}`, + ); } // make sure that it gets out of the "Creating" state @@ -109,4 +112,3 @@ export async function createDevice ( return udid; } - diff --git a/lib/subcommands/delete.ts b/lib/subcommands/delete.ts index 42c0a1f..ad116b0 100644 --- a/lib/subcommands/delete.ts +++ b/lib/subcommands/delete.ts @@ -1,4 +1,4 @@ -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Delete the particular Simulator from available devices list. @@ -7,9 +7,8 @@ import type { Simctl } from '../simctl'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function deleteDevice (this: Simctl): Promise { +export async function deleteDevice(this: Simctl): Promise { await this.exec('delete', { - args: [this.requireUdid('delete')] + args: [this.requireUdid('delete')], }); } - diff --git a/lib/subcommands/erase.ts b/lib/subcommands/erase.ts index 19a0129..672607e 100644 --- a/lib/subcommands/erase.ts +++ b/lib/subcommands/erase.ts @@ -1,5 +1,5 @@ -import { retryInterval } from 'asyncbox'; -import type { Simctl } from '../simctl'; +import {retryInterval} from 'asyncbox'; +import type {Simctl} from '../simctl'; /** * Reset the content and settings of the particular Simulator. @@ -11,13 +11,15 @@ import type { Simctl } from '../simctl'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function eraseDevice (this: Simctl, timeout: number = 1000): Promise { +export async function eraseDevice(this: Simctl, timeout: number = 1000): Promise { // retry erase with a sleep in between because it's flakey const retries = parseInt(`${timeout / 200}`, 10); - await retryInterval(retries, 200, - async () => await this.exec('erase', { - args: [this.requireUdid('erase')] - }) + await retryInterval( + retries, + 200, + async () => + await this.exec('erase', { + args: [this.requireUdid('erase')], + }), ); } - diff --git a/lib/subcommands/get_app_container.ts b/lib/subcommands/get_app_container.ts index 6b9761b..d0ebd5b 100644 --- a/lib/subcommands/get_app_container.ts +++ b/lib/subcommands/get_app_container.ts @@ -1,4 +1,4 @@ -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Get the full path to the particular application container @@ -17,10 +17,10 @@ import type { Simctl } from '../simctl'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function getAppContainer ( +export async function getAppContainer( this: Simctl, bundleId: string, - containerType: string | null = null + containerType: string | null = null, ): Promise { const args = [this.requireUdid('get_app_container'), bundleId]; if (containerType) { @@ -29,4 +29,3 @@ export async function getAppContainer ( const {stdout} = await this.exec('get_app_container', {args}); return (stdout || '').trim(); } - diff --git a/lib/subcommands/getenv.ts b/lib/subcommands/getenv.ts index 60a3bb1..42a49bc 100644 --- a/lib/subcommands/getenv.ts +++ b/lib/subcommands/getenv.ts @@ -1,4 +1,4 @@ -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Retrieves the value of a Simulator environment variable @@ -9,11 +9,10 @@ import type { Simctl } from '../simctl'; * @throws {Error} If there was an error while running the command * @throws {Error} If the `udid` instance property is unset */ -export async function getEnv (this: Simctl, varName: string): Promise { +export async function getEnv(this: Simctl, varName: string): Promise { const {stdout, stderr} = await this.exec('getenv', { args: [this.requireUdid('getenv'), varName], logErrors: false, }); return stderr ? null : stdout; } - diff --git a/lib/subcommands/install.ts b/lib/subcommands/install.ts index a259339..a4adf28 100644 --- a/lib/subcommands/install.ts +++ b/lib/subcommands/install.ts @@ -1,4 +1,4 @@ -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Install the particular application package on Simulator. @@ -10,9 +10,8 @@ import type { Simctl } from '../simctl'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function installApp (this: Simctl, appPath: string): Promise { +export async function installApp(this: Simctl, appPath: string): Promise { await this.exec('install', { args: [this.requireUdid('install'), appPath], }); } - diff --git a/lib/subcommands/io.ts b/lib/subcommands/io.ts index 404c84b..3c0ddd0 100644 --- a/lib/subcommands/io.ts +++ b/lib/subcommands/io.ts @@ -1,9 +1,9 @@ -import { rimraf } from 'rimraf'; +import {rimraf} from 'rimraf'; import path from 'node:path'; import os from 'node:os'; import fs from 'node:fs/promises'; -import { uuidV4 } from '../helpers'; -import type { Simctl } from '../simctl'; +import {uuidV4} from '../helpers'; +import type {Simctl} from '../simctl'; /** * Gets base64 screenshot for device @@ -15,7 +15,7 @@ import type { Simctl } from '../simctl'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function getScreenshot (this: Simctl): Promise { +export async function getScreenshot(this: Simctl): Promise { const udid = this.requireUdid('io screenshot'); const pathToScreenshotPng = path.resolve(os.tmpdir(), `${await uuidV4()}.png`); try { @@ -27,4 +27,3 @@ export async function getScreenshot (this: Simctl): Promise { await rimraf(pathToScreenshotPng); } } - diff --git a/lib/subcommands/keychain.ts b/lib/subcommands/keychain.ts index 6be8d48..486d94d 100644 --- a/lib/subcommands/keychain.ts +++ b/lib/subcommands/keychain.ts @@ -1,19 +1,19 @@ import os from 'node:os'; import fs from 'node:fs/promises'; -import { uuidV4 } from '../helpers'; +import {uuidV4} from '../helpers'; import path from 'node:path'; import _ from 'lodash'; -import { rimraf } from 'rimraf'; -import type { Simctl } from '../simctl'; -import type { CertOptions } from '../types'; +import {rimraf} from 'rimraf'; +import type {Simctl} from '../simctl'; +import type {CertOptions} from '../types'; /** * @param payload - Certificate payload (string or Buffer) * @param onPayloadStored - Callback function to execute with the file path */ -async function handleRawPayload ( +async function handleRawPayload( payload: string | Buffer, - onPayloadStored: (filePath: string) => Promise + onPayloadStored: (filePath: string) => Promise, ): Promise { const filePath = path.resolve(os.tmpdir(), `${await uuidV4()}.pem`); try { @@ -40,17 +40,16 @@ async function handleRawPayload ( * or there was an error while adding the certificate * @throws {Error} If the `udid` instance property is unset */ -export async function addRootCertificate ( +export async function addRootCertificate( this: Simctl, cert: string | Buffer, - opts: CertOptions = {} + opts: CertOptions = {}, ): Promise { - const { - raw = false, - } = opts; - const execMethod = async (certPath: string) => await this.exec('keychain', { - args: [this.requireUdid('keychain add-root-cert'), 'add-root-cert', certPath], - }); + const {raw = false} = opts; + const execMethod = async (certPath: string) => + await this.exec('keychain', { + args: [this.requireUdid('keychain add-root-cert'), 'add-root-cert', certPath], + }); if (raw) { await handleRawPayload(cert, execMethod); } else { @@ -70,17 +69,16 @@ export async function addRootCertificate ( * or there was an error while adding the certificate * @throws {Error} If the `udid` instance property is unset */ -export async function addCertificate ( +export async function addCertificate( this: Simctl, cert: string | Buffer, - opts: CertOptions = {} + opts: CertOptions = {}, ): Promise { - const { - raw = false, - } = opts; - const execMethod = async (certPath: string) => await this.exec('keychain', { - args: [this.requireUdid('keychain add-cert'), 'add-cert', certPath], - }); + const {raw = false} = opts; + const execMethod = async (certPath: string) => + await this.exec('keychain', { + args: [this.requireUdid('keychain add-cert'), 'add-cert', certPath], + }); if (raw) { await handleRawPayload(cert, execMethod); } else { @@ -96,9 +94,8 @@ export async function addCertificate ( * or there was an error while resetting the keychain * @throws {Error} If the `udid` instance property is unset */ -export async function resetKeychain (this: Simctl): Promise { +export async function resetKeychain(this: Simctl): Promise { await this.exec('keychain', { args: [this.requireUdid('keychain reset'), 'reset'], }); } - diff --git a/lib/subcommands/launch.ts b/lib/subcommands/launch.ts index 37df92c..09c0bf9 100644 --- a/lib/subcommands/launch.ts +++ b/lib/subcommands/launch.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; -import { retryInterval } from 'asyncbox'; -import type { Simctl } from '../simctl'; +import {retryInterval} from 'asyncbox'; +import type {Simctl} from '../simctl'; /** * Execute the particular application package on Simulator. @@ -16,7 +16,11 @@ import type { Simctl } from '../simctl'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function launchApp (this: Simctl, bundleId: string, tries: number = 5): Promise { +export async function launchApp( + this: Simctl, + bundleId: string, + tries: number = 5, +): Promise { const result = await retryInterval(tries, 1000, async () => { const {stdout} = await this.exec('launch', { args: [this.requireUdid('launch'), bundleId], @@ -25,4 +29,3 @@ export async function launchApp (this: Simctl, bundleId: string, tries: number = }); return result || ''; } - diff --git a/lib/subcommands/list.ts b/lib/subcommands/list.ts index 413c68b..288e148 100644 --- a/lib/subcommands/list.ts +++ b/lib/subcommands/list.ts @@ -1,8 +1,8 @@ import _ from 'lodash'; -import { SIM_RUNTIME_NAME, normalizeVersion } from '../helpers'; -import { log, LOG_PREFIX } from '../logger'; -import type { Simctl } from '../simctl'; -import type { DeviceInfo } from '../types'; +import {SIM_RUNTIME_NAME, normalizeVersion} from '../helpers'; +import {log, LOG_PREFIX} from '../logger'; +import type {Simctl} from '../simctl'; +import type {DeviceInfo} from '../types'; /** * Parse the list of existing Simulator devices to represent @@ -15,9 +15,9 @@ import type { DeviceInfo } from '../types'; * @throws {Error} If the corresponding simctl subcommand command * returns non-zero return code. */ -export async function getDevicesByParsing ( +export async function getDevicesByParsing( this: Simctl, - platform?: string | null + platform?: string | null, ): Promise> { const {stdout} = await this.exec('list', { args: ['devices'], @@ -32,9 +32,13 @@ export async function getDevicesByParsing ( // ... // so, get the `-- iOS X.X --` line to find the sdk (X.X) // and the rest of the listing in order to later find the devices - const deviceSectionRe = _.isEmpty(platform) || !platform - ? new RegExp(`\\-\\-\\s+(\\S+)\\s+(\\S+)\\s+\\-\\-(\\n\\s{4}.+)*`, 'mgi') - : new RegExp(`\\-\\-\\s+${_.escapeRegExp(platform)}\\s+(\\S+)\\s+\\-\\-(\\n\\s{4}.+)*`, 'mgi'); + const deviceSectionRe = + _.isEmpty(platform) || !platform + ? new RegExp(`\\-\\-\\s+(\\S+)\\s+(\\S+)\\s+\\-\\-(\\n\\s{4}.+)*`, 'mgi') + : new RegExp( + `\\-\\-\\s+${_.escapeRegExp(platform)}\\s+(\\S+)\\s+\\-\\-(\\n\\s{4}.+)*`, + 'mgi', + ); const matches: RegExpExecArray[] = []; let match: RegExpExecArray | null; // make an entry for each sdk version @@ -95,20 +99,20 @@ export async function getDevicesByParsing ( * returns non-zero return code or if no matching * platform version is found in the system. */ -export async function getDevices ( +export async function getDevices( this: Simctl, forSdk: string, - platform?: string | null + platform?: string | null, ): Promise; -export async function getDevices ( +export async function getDevices( this: Simctl, forSdk?: undefined | null, - platform?: string | null + platform?: string | null, ): Promise>; -export async function getDevices ( +export async function getDevices( this: Simctl, forSdk?: string | null, - platform?: string | null + platform?: string | null, ): Promise | DeviceInfo[]> { let devices: Record = {}; try { @@ -131,9 +135,10 @@ export async function getDevices ( * } * } */ - const versionMatchRe = _.isEmpty(platform) || !platform - ? new RegExp(`^([^\\s-]+)[\\s-](\\S+)`, 'i') - : new RegExp(`^${_.escapeRegExp(platform)}[\\s-](\\S+)`, 'i'); + const versionMatchRe = + _.isEmpty(platform) || !platform + ? new RegExp(`^([^\\s-]+)[\\s-](\\S+)`, 'i') + : new RegExp(`^${_.escapeRegExp(platform)}[\\s-](\\S+)`, 'i'); for (const [sdkNameRaw, entries] of _.toPairs(JSON.parse(stdout).devices)) { // there could be a longer name, so remove it const sdkName = sdkNameRaw.replace(SIM_RUNTIME_NAME, ''); @@ -145,15 +150,17 @@ export async function getDevices ( // the sdk can have dashes (`12-2`) or dots (`12.1`) const sdk = (platform ? versionMatch[1] : versionMatch[2]).replace('-', '.'); devices[sdk] = devices[sdk] || []; - devices[sdk].push(...(entries as any[]).filter((el) => _.isUndefined(el.isAvailable) || el.isAvailable) - .map((el: any) => { - delete el.availability; - return { - sdk, - ...el, - platform: platform || versionMatch[1], - }; - }) + devices[sdk].push( + ...(entries as any[]) + .filter((el) => _.isUndefined(el.isAvailable) || el.isAvailable) + .map((el: any) => { + delete el.availability; + return { + sdk, + ...el, + platform: platform || versionMatch[1], + }; + }), ); } } catch (err: any) { @@ -187,17 +194,19 @@ export async function getDevices ( * @return The corresponding runtime name for the given * platform version. */ -export async function getRuntimeForPlatformVersionViaJson ( +export async function getRuntimeForPlatformVersionViaJson( this: Simctl, platformVersion: string, - platform: string = 'iOS' + platform: string = 'iOS', ): Promise { const {stdout} = await this.exec('list', { args: ['runtimes', '--json'], }); for (const {version, identifier, name} of JSON.parse(stdout).runtimes) { - if (normalizeVersion(version) === normalizeVersion(platformVersion) - && name.toLowerCase().startsWith(platform.toLowerCase())) { + if ( + normalizeVersion(version) === normalizeVersion(platformVersion) && + name.toLowerCase().startsWith(platform.toLowerCase()) + ) { return identifier; } } @@ -213,10 +222,10 @@ export async function getRuntimeForPlatformVersionViaJson ( * @return The corresponding runtime name for the given * platform version. */ -export async function getRuntimeForPlatformVersion ( +export async function getRuntimeForPlatformVersion( this: Simctl, platformVersion: string, - platform: string = 'iOS' + platform: string = 'iOS', ): Promise { // Try with parsing try { @@ -224,8 +233,10 @@ export async function getRuntimeForPlatformVersion ( args: ['runtimes'], }); // https://regex101.com/r/UykjQZ/1 - const runtimeRe = - new RegExp(`${_.escapeRegExp(platform)}\\s+(\\d+\\.\\d+)\\s+\\((\\d+\\.\\d+\\.*\\d*)`, 'i'); + const runtimeRe = new RegExp( + `${_.escapeRegExp(platform)}\\s+(\\d+\\.\\d+)\\s+\\((\\d+\\.\\d+\\.*\\d*)`, + 'i', + ); for (const line of stdout.split('\n')) { const match = runtimeRe.exec(line); if (match && match[1] === platformVersion) { @@ -244,7 +255,7 @@ export async function getRuntimeForPlatformVersion ( * @return List of the types of devices available * @throws {Error} If the corresponding simctl command fails */ -export async function getDeviceTypes (this: Simctl): Promise { +export async function getDeviceTypes(this: Simctl): Promise { const {stdout} = await this.exec('list', { args: ['devicetypes', '-j'], }); @@ -301,7 +312,7 @@ export async function getDeviceTypes (this: Simctl): Promise { * } * @throws {Error} If the corresponding simctl command fails */ -export async function list (this: Simctl): Promise { +export async function list(this: Simctl): Promise { const {stdout} = await this.exec('list', { args: ['-j'], }); @@ -311,4 +322,3 @@ export async function list (this: Simctl): Promise { throw new Error(`Unable to parse simctl list: ${e.message}`); } } - diff --git a/lib/subcommands/location.ts b/lib/subcommands/location.ts index fcae077..a302b16 100644 --- a/lib/subcommands/location.ts +++ b/lib/subcommands/location.ts @@ -1,4 +1,4 @@ -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Formats the given location argument for simctl usage @@ -7,7 +7,7 @@ import type { Simctl } from '../simctl'; * @param value Location argument value * @returns Formatted value, for example -73.768254 */ -function formatArg (name: string, value: string | number): string { +function formatArg(name: string, value: string | number): string { const flt = parseFloat(`${value}`); if (isNaN(flt)) { throw new TypeError(`${name} must be a valid number, got '${value}' instead`); @@ -25,10 +25,10 @@ function formatArg (name: string, value: string | number): string { * returns non-zero return code. * @throws {TypeError} If any of the arguments is not a valid value. */ -export async function setLocation ( +export async function setLocation( this: Simctl, latitude: string | number, - longitude: string | number + longitude: string | number, ): Promise { const lat = formatArg('latitude', latitude); const lon = formatArg('longitude', longitude); @@ -42,9 +42,8 @@ export async function setLocation ( * * @since Xcode 14. */ -export async function clearLocation (this: Simctl): Promise { +export async function clearLocation(this: Simctl): Promise { await this.exec('location', { args: [this.requireUdid('location'), 'clear'], }); } - diff --git a/lib/subcommands/openurl.ts b/lib/subcommands/openurl.ts index 550b31d..8734ecc 100644 --- a/lib/subcommands/openurl.ts +++ b/lib/subcommands/openurl.ts @@ -1,5 +1,5 @@ -import type { Simctl } from '../simctl'; -import type { TeenProcessExecResult } from 'teen_process'; +import type {Simctl} from '../simctl'; +import type {TeenProcessExecResult} from 'teen_process'; /** * Open URL scheme on Simulator. iOS will automatically try @@ -13,7 +13,7 @@ import type { TeenProcessExecResult } from 'teen_process'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function openUrl (this: Simctl, url: string): Promise> { +export async function openUrl(this: Simctl, url: string): Promise> { return await this.exec('openurl', { args: [this.requireUdid('openurl'), url], }); diff --git a/lib/subcommands/pbcopy.ts b/lib/subcommands/pbcopy.ts index ce914d9..29f1aed 100644 --- a/lib/subcommands/pbcopy.ts +++ b/lib/subcommands/pbcopy.ts @@ -1,5 +1,5 @@ -import type { Simctl } from '../simctl'; -import type { SubProcess } from 'teen_process'; +import type {Simctl} from '../simctl'; +import type {SubProcess} from 'teen_process'; /** * Set the content of Simulator pasteboard. @@ -13,15 +13,15 @@ import type { SubProcess } from 'teen_process'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function setPasteboard ( +export async function setPasteboard( this: Simctl, content: string, - encoding: BufferEncoding = 'utf8' + encoding: BufferEncoding = 'utf8', ): Promise { - const pbCopySubprocess = await this.exec('pbcopy', { + const pbCopySubprocess = (await this.exec('pbcopy', { args: [this.requireUdid('pbcopy')], asynchronous: true, - }) as SubProcess; + })) as SubProcess; await pbCopySubprocess.start(0); const exitCodeVerifier = pbCopySubprocess.join(); const stdin = pbCopySubprocess.proc?.stdin; @@ -32,4 +32,3 @@ export async function setPasteboard ( } await exitCodeVerifier; } - diff --git a/lib/subcommands/pbpaste.ts b/lib/subcommands/pbpaste.ts index 230a005..5e890c8 100644 --- a/lib/subcommands/pbpaste.ts +++ b/lib/subcommands/pbpaste.ts @@ -1,4 +1,4 @@ -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Get the content of Simulator pasteboard. @@ -12,11 +12,13 @@ import type { Simctl } from '../simctl'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function getPasteboard (this: Simctl, encoding: BufferEncoding = 'utf8'): Promise { +export async function getPasteboard( + this: Simctl, + encoding: BufferEncoding = 'utf8', +): Promise { const {stdout} = await this.exec('pbpaste', { args: [this.requireUdid('pbpaste')], encoding, }); return stdout; } - diff --git a/lib/subcommands/privacy.ts b/lib/subcommands/privacy.ts index 180c1fd..7526b2b 100644 --- a/lib/subcommands/privacy.ts +++ b/lib/subcommands/privacy.ts @@ -1,4 +1,4 @@ -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Grants the given permission on the app with the given bundle identifier @@ -24,7 +24,7 @@ import type { Simctl } from '../simctl'; * or there was an error while granting the permission * @throws {Error} If the `udid` instance property is unset */ -export async function grantPermission (this: Simctl, bundleId: string, perm: string): Promise { +export async function grantPermission(this: Simctl, bundleId: string, perm: string): Promise { await this.exec('privacy', { args: [this.requireUdid('privacy grant'), 'grant', perm, bundleId], }); @@ -42,7 +42,11 @@ export async function grantPermission (this: Simctl, bundleId: string, perm: str * or there was an error while revoking the permission * @throws {Error} If the `udid` instance property is unset */ -export async function revokePermission (this: Simctl, bundleId: string, perm: string): Promise { +export async function revokePermission( + this: Simctl, + bundleId: string, + perm: string, +): Promise { await this.exec('privacy', { args: [this.requireUdid('privacy revoke'), 'revoke', perm, bundleId], }); @@ -60,9 +64,8 @@ export async function revokePermission (this: Simctl, bundleId: string, perm: st * or there was an error while resetting the permission * @throws {Error} If the `udid` instance property is unset */ -export async function resetPermission (this: Simctl, bundleId: string, perm: string): Promise { +export async function resetPermission(this: Simctl, bundleId: string, perm: string): Promise { await this.exec('privacy', { args: [this.requireUdid('private reset'), 'reset', perm, bundleId], }); } - diff --git a/lib/subcommands/push.ts b/lib/subcommands/push.ts index 00792fe..9fff997 100644 --- a/lib/subcommands/push.ts +++ b/lib/subcommands/push.ts @@ -1,9 +1,9 @@ -import { rimraf } from 'rimraf'; -import { uuidV4 } from '../helpers'; +import {rimraf} from 'rimraf'; +import {uuidV4} from '../helpers'; import path from 'node:path'; import os from 'node:os'; import fs from 'node:fs/promises'; -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Send a simulated push notification @@ -25,7 +25,7 @@ import type { Simctl } from '../simctl'; * or there was an error while pushing the notification * @throws {Error} If the `udid` instance property is unset */ -export async function pushNotification (this: Simctl, payload: Record): Promise { +export async function pushNotification(this: Simctl, payload: Record): Promise { const dstPath = path.resolve(os.tmpdir(), `${await uuidV4()}.json`); try { await fs.writeFile(dstPath, JSON.stringify(payload), 'utf8'); @@ -36,4 +36,3 @@ export async function pushNotification (this: Simctl, payload: Record { +export async function shutdownDevice(this: Simctl): Promise { try { await this.exec('shutdown', { args: [this.requireUdid('shutdown')], @@ -21,4 +21,3 @@ export async function shutdownDevice (this: Simctl): Promise { log.debug(LOG_PREFIX, `Simulator already in 'Shutdown' state. Continuing`); } } - diff --git a/lib/subcommands/spawn.ts b/lib/subcommands/spawn.ts index b38b7f1..d5406b9 100644 --- a/lib/subcommands/spawn.ts +++ b/lib/subcommands/spawn.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; -import type { Simctl } from '../simctl'; -import type { TeenProcessExecResult, SubProcess } from 'teen_process'; +import type {Simctl} from '../simctl'; +import type {TeenProcessExecResult, SubProcess} from 'teen_process'; /** * Spawn the particular process on Simulator. @@ -13,10 +13,10 @@ import type { TeenProcessExecResult, SubProcess } from 'teen_process'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function spawnProcess ( +export async function spawnProcess( this: Simctl, args: string | string[], - env: Record = {} + env: Record = {}, ): Promise> { if (_.isEmpty(args)) { throw new Error('Spawn arguments are required'); @@ -37,19 +37,18 @@ export async function spawnProcess ( * @return The instance of the process to be spawned. * @throws {Error} If the `udid` instance property is unset */ -export async function spawnSubProcess ( +export async function spawnSubProcess( this: Simctl, args: string | string[], - env: Record = {} + env: Record = {}, ): Promise { if (_.isEmpty(args)) { throw new Error('Spawn arguments are required'); } - return await this.exec('spawn', { + return (await this.exec('spawn', { args: [this.requireUdid('spawn'), ...(_.isArray(args) ? args : [args])], env, asynchronous: true, - }) as SubProcess; + })) as SubProcess; } - diff --git a/lib/subcommands/terminate.ts b/lib/subcommands/terminate.ts index 7a12683..5537f91 100644 --- a/lib/subcommands/terminate.ts +++ b/lib/subcommands/terminate.ts @@ -1,4 +1,4 @@ -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Terminate the given running application on Simulator. @@ -10,9 +10,8 @@ import type { Simctl } from '../simctl'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function terminateApp (this: Simctl, bundleId: string): Promise { +export async function terminateApp(this: Simctl, bundleId: string): Promise { await this.exec('terminate', { args: [this.requireUdid('terminate'), bundleId], }); } - diff --git a/lib/subcommands/ui.ts b/lib/subcommands/ui.ts index 059a987..1f39d1d 100644 --- a/lib/subcommands/ui.ts +++ b/lib/subcommands/ui.ts @@ -1,5 +1,5 @@ import _ from 'lodash'; -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Retrieves the current UI appearance value from the given simulator @@ -10,7 +10,7 @@ import type { Simctl } from '../simctl'; * or there was an error while getting the value * @throws {Error} If the `udid` instance property is unset */ -export async function getAppearance (this: Simctl): Promise { +export async function getAppearance(this: Simctl): Promise { const {stdout} = await this.exec('ui', { args: [this.requireUdid('ui'), 'appearance'], }); @@ -26,7 +26,7 @@ export async function getAppearance (this: Simctl): Promise { * or there was an error while getting the value * @throws {Error} If the `udid` instance property is unset */ -export async function setAppearance (this: Simctl, appearance: string): Promise { +export async function setAppearance(this: Simctl, appearance: string): Promise { await this.exec('ui', { args: [this.requireUdid('ui'), 'appearance', appearance], }); @@ -48,7 +48,7 @@ export async function setAppearance (this: Simctl, appearance: string): Promise< * or there was an error while getting the value. * @throws {Error} If the `udid` instance property is unset */ -export async function getIncreaseContrast (this: Simctl): Promise { +export async function getIncreaseContrast(this: Simctl): Promise { const {stdout} = await this.exec('ui', { args: [this.requireUdid('ui'), 'increase_contrast'], }); @@ -68,7 +68,7 @@ export async function getIncreaseContrast (this: Simctl): Promise { * or the given value was invalid for the command. * @throws {Error} If the `udid` instance property is unset */ -export async function setIncreaseContrast (this: Simctl, increaseContrast: string): Promise { +export async function setIncreaseContrast(this: Simctl, increaseContrast: string): Promise { await this.exec('ui', { args: [this.requireUdid('ui'), 'increase_contrast', increaseContrast], }); @@ -95,7 +95,7 @@ export async function setIncreaseContrast (this: Simctl, increaseContrast: strin * or there was an error while getting the value. * @throws {Error} If the `udid` instance property is unset */ -export async function getContentSize (this: Simctl): Promise { +export async function getContentSize(this: Simctl): Promise { const {stdout} = await this.exec('ui', { args: [this.requireUdid('ui'), 'content_size'], }); @@ -124,9 +124,8 @@ export async function getContentSize (this: Simctl): Promise { * or the given value was invalid for the command. * @throws {Error} If the `udid` instance property is unset */ -export async function setContentSize (this: Simctl, contentSizeAction: string): Promise { +export async function setContentSize(this: Simctl, contentSizeAction: string): Promise { await this.exec('ui', { args: [this.requireUdid('ui'), 'content_size', contentSizeAction], }); } - diff --git a/lib/subcommands/uninstall.ts b/lib/subcommands/uninstall.ts index d998066..edb1929 100644 --- a/lib/subcommands/uninstall.ts +++ b/lib/subcommands/uninstall.ts @@ -1,4 +1,4 @@ -import type { Simctl } from '../simctl'; +import type {Simctl} from '../simctl'; /** * Remove the particular application package from Simulator. @@ -11,9 +11,8 @@ import type { Simctl } from '../simctl'; * returns non-zero return code. * @throws {Error} If the `udid` instance property is unset */ -export async function removeApp (this: Simctl, bundleId: string): Promise { +export async function removeApp(this: Simctl, bundleId: string): Promise { await this.exec('uninstall', { args: [this.requireUdid('uninstall'), bundleId], }); } - diff --git a/lib/types.ts b/lib/types.ts index 8630998..c8d3914 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,4 +1,4 @@ -import type { SubProcess, TeenProcessExecResult } from 'teen_process'; +import type {SubProcess, TeenProcessExecResult} from 'teen_process'; /** * XCRun configuration @@ -240,4 +240,3 @@ export interface AppInfo { */ SBAppTags?: string[]; } - diff --git a/package.json b/package.json index 6d12a54..65bc1a1 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,8 @@ "dev": "npm run build -- --watch", "lint": "eslint .", "lint:fix": "npm run lint -- --fix", + "format": "prettier -w ./lib ./test", + "format:check": "prettier --check ./lib ./test", "prepare": "npm run build", "test": "mocha --exit --timeout 1m \"./test/unit/**/*-specs.ts\"", "e2e-test": "mocha --exit --timeout 5m \"./test/e2e/**/*-specs.ts\"" diff --git a/test/e2e/simctl-e2e-specs.ts b/test/e2e/simctl-e2e-specs.ts index e7a500e..ced15a6 100644 --- a/test/e2e/simctl-e2e-specs.ts +++ b/test/e2e/simctl-e2e-specs.ts @@ -1,13 +1,13 @@ import _ from 'lodash'; -import { Simctl } from '../../lib/simctl'; +import {Simctl} from '../../lib/simctl'; import xcode from 'appium-xcode'; -import { retryInterval } from 'asyncbox'; -import { rimraf } from 'rimraf'; -import { uuidV4 } from '../../lib/helpers'; +import {retryInterval} from 'asyncbox'; +import {rimraf} from 'rimraf'; +import {uuidV4} from '../../lib/helpers'; import path from 'node:path'; import os from 'node:os'; import fs from 'node:fs/promises'; -import { expect, use } from 'chai'; +import {expect, use} from 'chai'; import chaiAsPromised from 'chai-as-promised'; use(chaiAsPromised); @@ -23,7 +23,6 @@ describe('simctl', function () { let simctl: Simctl; before(async function () { - simctl = new Simctl(); const devices = await simctl.getDevices(); console.log(`Found devices: ${JSON.stringify(devices, null, 2)}`); // eslint-disable-line no-console @@ -214,14 +213,19 @@ describe('simctl', function () { }); describe('add media', function () { - const BASE64_PNG = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; + const BASE64_PNG = + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; let picturePath: string | undefined; before(async function () { if (major < 8 || (major === 8 && minor < 1)) { return this.skip(); } picturePath = path.join(os.tmpdir(), `${await uuidV4()}.png`); - await fs.writeFile(picturePath, Buffer.from(BASE64_PNG, 'base64').toString('binary'), 'binary'); + await fs.writeFile( + picturePath, + Buffer.from(BASE64_PNG, 'base64').toString('binary'), + 'binary', + ); }); after(async function () { if (picturePath) { @@ -273,13 +277,17 @@ describe('simctl', function () { expect(fullList).to.have.property('pairs'); expect(fullList.devicetypes.length).to.be.above(1); // at least one type, no matter the version of Xcode, should be an iPhone - expect(fullList.devicetypes.filter((el) => el.identifier.includes('iPhone')).length).to.be.above(0); + expect( + fullList.devicetypes.filter((el) => el.identifier.includes('iPhone')).length, + ).to.be.above(0); // at least one runtime should be iOS - expect(fullList.runtimes.filter((el) => el.identifier.includes('iOS')).length).to.be.above(0); + expect(fullList.runtimes.filter((el) => el.identifier.includes('iOS')).length).to.be.above( + 0, + ); }); }); - describe('getScreenshot', function() { + describe('getScreenshot', function () { it('should get a base64 string', async function () { const image = await simctl.getScreenshot(); @@ -287,7 +295,7 @@ describe('simctl', function () { }); }); - describe('pushNotification', function() { + describe('pushNotification', function () { it('should not throw an error when sending a push notification', async function () { if (process.env.CI) { // This test is unstable in CI env @@ -296,11 +304,11 @@ describe('simctl', function () { const payload = { 'Simulator Target Bundle': 'com.apple.Preferences', - 'aps': { - 'alert': 'This is a simulated notification!', - 'badge': 3, - 'sound': 'default' - } + aps: { + alert: 'This is a simulated notification!', + badge: 3, + sound: 'default', + }, }; await expect(simctl.pushNotification(payload)).to.be.fulfilled; @@ -308,4 +316,3 @@ describe('simctl', function () { }); }); }); - diff --git a/test/unit/fixtures/devices-simple.json b/test/unit/fixtures/devices-simple.json index bca90f4..d27d2d8 100644 --- a/test/unit/fixtures/devices-simple.json +++ b/test/unit/fixtures/devices-simple.json @@ -1,137 +1,137 @@ { - "devices" : { - "tvOS 12.1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV", - "udid" : "FA628127-1D5C-45C3-9918-A47BF7E2AE14", - "availabilityError" : "" + "devices": { + "tvOS 12.1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV", + "udid": "FA628127-1D5C-45C3-9918-A47BF7E2AE14", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV 4K", - "udid" : "2EF493BE-E7D5-45E7-9725-8D2706F7220E", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV 4K", + "udid": "2EF493BE-E7D5-45E7-9725-8D2706F7220E", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV 4K (at 1080p)", - "udid" : "FFECD143-B523-4A3D-BA27-1F9706F814CB", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV 4K (at 1080p)", + "udid": "FFECD143-B523-4A3D-BA27-1F9706F814CB", + "availabilityError": "" } ], - "iOS 12.1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 5s", - "udid" : "E17597CE-71EE-4402-8B1C-1B526446A3A2", - "availabilityError" : "" + "iOS 12.1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 5s", + "udid": "E17597CE-71EE-4402-8B1C-1B526446A3A2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 6", - "udid" : "1C7AB8B9-94C3-4806-86D7-77C13B483902", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 6", + "udid": "1C7AB8B9-94C3-4806-86D7-77C13B483902", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 6 Plus", - "udid" : "EE76EA77-E975-4198-9859-69DFF74252D2", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 6 Plus", + "udid": "EE76EA77-E975-4198-9859-69DFF74252D2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Air", - "udid" : "225C4FDB-5132-423A-9CFF-89D4474395F9", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Air", + "udid": "225C4FDB-5132-423A-9CFF-89D4474395F9", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Air 2", - "udid" : "DDDF281C-F912-471C-B30D-994A2644DF03", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Air 2", + "udid": "DDDF281C-F912-471C-B30D-994A2644DF03", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Pro (12.9-inch)", - "udid" : "1D953CFF-1FBC-413E-B2AB-B4BA4DD5EEC2", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Pro (12.9-inch)", + "udid": "1D953CFF-1FBC-413E-B2AB-B4BA4DD5EEC2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Pro (12.9-inch) (2nd generation)", - "udid" : "A7D1A0D7-D67B-409F-A73D-0DB53EDD860F", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Pro (12.9-inch) (2nd generation)", + "udid": "A7D1A0D7-D67B-409F-A73D-0DB53EDD860F", + "availabilityError": "" } ], - "watchOS 5.1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "F40113CC-2973-4EBD-87F4-31852A6FF09B", - "availabilityError" : "" + "watchOS 5.1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 2 - 38mm", + "udid": "F40113CC-2973-4EBD-87F4-31852A6FF09B", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "5A83C524-FFF6-45AA-936C-365D2F1126F3", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 2 - 42mm", + "udid": "5A83C524-FFF6-45AA-936C-365D2F1126F3", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 3 - 38mm", - "udid" : "C76C585D-96D1-4037-80ED-C73DBBDB3521", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 3 - 38mm", + "udid": "C76C585D-96D1-4037-80ED-C73DBBDB3521", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 3 - 42mm", - "udid" : "DA5E98A8-2D04-474F-A0C3-9A0234F44CC9", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 3 - 42mm", + "udid": "DA5E98A8-2D04-474F-A0C3-9A0234F44CC9", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 4 - 40mm", - "udid" : "DCD321B8-F265-4213-B248-C89AB8B806E1", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 4 - 40mm", + "udid": "DCD321B8-F265-4213-B248-C89AB8B806E1", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 4 - 44mm", - "udid" : "EADBBE94-E97C-4D13-9FF2-44A3524113C7", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 4 - 44mm", + "udid": "EADBBE94-E97C-4D13-9FF2-44A3524113C7", + "availabilityError": "" } ] } diff --git a/test/unit/fixtures/devices-with-unavailable-simple.json b/test/unit/fixtures/devices-with-unavailable-simple.json index 0f2af33..bcfb002 100644 --- a/test/unit/fixtures/devices-with-unavailable-simple.json +++ b/test/unit/fixtures/devices-with-unavailable-simple.json @@ -1,271 +1,271 @@ { - "devices" : { - "tvOS 12.1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV", - "udid" : "FA628127-1D5C-45C3-9918-A47BF7E2AE14", - "availabilityError" : "" + "devices": { + "tvOS 12.1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV", + "udid": "FA628127-1D5C-45C3-9918-A47BF7E2AE14", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV 4K", - "udid" : "2EF493BE-E7D5-45E7-9725-8D2706F7220E", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV 4K", + "udid": "2EF493BE-E7D5-45E7-9725-8D2706F7220E", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV 4K (at 1080p)", - "udid" : "FFECD143-B523-4A3D-BA27-1F9706F814CB", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV 4K (at 1080p)", + "udid": "FFECD143-B523-4A3D-BA27-1F9706F814CB", + "availabilityError": "" } ], - "iOS 12.1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 5s", - "udid" : "E17597CE-71EE-4402-8B1C-1B526446A3A2", - "availabilityError" : "" + "iOS 12.1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 5s", + "udid": "E17597CE-71EE-4402-8B1C-1B526446A3A2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 6", - "udid" : "1C7AB8B9-94C3-4806-86D7-77C13B483902", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 6", + "udid": "1C7AB8B9-94C3-4806-86D7-77C13B483902", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 6 Plus", - "udid" : "EE76EA77-E975-4198-9859-69DFF74252D2", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 6 Plus", + "udid": "EE76EA77-E975-4198-9859-69DFF74252D2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Air", - "udid" : "225C4FDB-5132-423A-9CFF-89D4474395F9", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Air", + "udid": "225C4FDB-5132-423A-9CFF-89D4474395F9", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Air 2", - "udid" : "DDDF281C-F912-471C-B30D-994A2644DF03", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Air 2", + "udid": "DDDF281C-F912-471C-B30D-994A2644DF03", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Pro (12.9-inch)", - "udid" : "1D953CFF-1FBC-413E-B2AB-B4BA4DD5EEC2", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Pro (12.9-inch)", + "udid": "1D953CFF-1FBC-413E-B2AB-B4BA4DD5EEC2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Pro (12.9-inch) (2nd generation)", - "udid" : "A7D1A0D7-D67B-409F-A73D-0DB53EDD860F", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Pro (12.9-inch) (2nd generation)", + "udid": "A7D1A0D7-D67B-409F-A73D-0DB53EDD860F", + "availabilityError": "" } ], - "tvOS 12.2" : [ - { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple TV", - "udid" : "84793AD4-E1C9-49EE-B85A-0DCBB0806279", - "availabilityError" : "runtime profile not found" + "tvOS 12.2": [ + { + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple TV", + "udid": "84793AD4-E1C9-49EE-B85A-0DCBB0806279", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple TV 4K", - "udid" : "B3ABE34D-7F23-4107-B381-3DD0184134D1", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple TV 4K", + "udid": "B3ABE34D-7F23-4107-B381-3DD0184134D1", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple TV 4K (at 1080p)", - "udid" : "289113A3-52A3-4904-B7B6-E66DF666EDB5", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple TV 4K (at 1080p)", + "udid": "289113A3-52A3-4904-B7B6-E66DF666EDB5", + "availabilityError": "runtime profile not found" } ], - "watchOS 5.2" : [ - { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "76D3F91D-5C60-4B9B-A30A-A01A63C6FE73", - "availabilityError" : "runtime profile not found" + "watchOS 5.2": [ + { + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 2 - 38mm", + "udid": "76D3F91D-5C60-4B9B-A30A-A01A63C6FE73", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "26B36BEB-A564-4321-A108-72DEEB2D63F9", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 2 - 42mm", + "udid": "26B36BEB-A564-4321-A108-72DEEB2D63F9", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 3 - 38mm", - "udid" : "63D10205-08E3-4A8C-9334-DB0868D87554", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 3 - 38mm", + "udid": "63D10205-08E3-4A8C-9334-DB0868D87554", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 3 - 42mm", - "udid" : "420CD468-9CED-44F7-A8AE-F1FABB18BFB2", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 3 - 42mm", + "udid": "420CD468-9CED-44F7-A8AE-F1FABB18BFB2", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 4 - 40mm", - "udid" : "6E507921-8AE9-4562-93C6-52DFDA87EA40", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 4 - 40mm", + "udid": "6E507921-8AE9-4562-93C6-52DFDA87EA40", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 4 - 44mm", - "udid" : "E5DDFDFA-693A-46A7-B42A-866681E15B83", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 4 - 44mm", + "udid": "E5DDFDFA-693A-46A7-B42A-866681E15B83", + "availabilityError": "runtime profile not found" } ], - "watchOS 5.1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "F40113CC-2973-4EBD-87F4-31852A6FF09B", - "availabilityError" : "" + "watchOS 5.1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 2 - 38mm", + "udid": "F40113CC-2973-4EBD-87F4-31852A6FF09B", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "5A83C524-FFF6-45AA-936C-365D2F1126F3", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 2 - 42mm", + "udid": "5A83C524-FFF6-45AA-936C-365D2F1126F3", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 3 - 38mm", - "udid" : "C76C585D-96D1-4037-80ED-C73DBBDB3521", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 3 - 38mm", + "udid": "C76C585D-96D1-4037-80ED-C73DBBDB3521", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 3 - 42mm", - "udid" : "DA5E98A8-2D04-474F-A0C3-9A0234F44CC9", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 3 - 42mm", + "udid": "DA5E98A8-2D04-474F-A0C3-9A0234F44CC9", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 4 - 40mm", - "udid" : "DCD321B8-F265-4213-B248-C89AB8B806E1", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 4 - 40mm", + "udid": "DCD321B8-F265-4213-B248-C89AB8B806E1", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 4 - 44mm", - "udid" : "EADBBE94-E97C-4D13-9FF2-44A3524113C7", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 4 - 44mm", + "udid": "EADBBE94-E97C-4D13-9FF2-44A3524113C7", + "availabilityError": "" } ], - "iOS 12.2" : [ - { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPhone 5s", - "udid" : "DBC918BB-D519-408D-A5E7-EAD66D875A40", - "availabilityError" : "runtime profile not found" + "iOS 12.2": [ + { + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPhone 5s", + "udid": "DBC918BB-D519-408D-A5E7-EAD66D875A40", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPhone 6", - "udid" : "5CC1A69E-75B0-4109-8474-61C605C61493", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPhone 6", + "udid": "5CC1A69E-75B0-4109-8474-61C605C61493", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPhone 6 Plus", - "udid" : "99FE1BB4-66F4-47CA-A144-9198A5CBB9B6", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPhone 6 Plus", + "udid": "99FE1BB4-66F4-47CA-A144-9198A5CBB9B6", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPad Air", - "udid" : "F78CD721-6DB1-4C19-9601-FEB84D2D0A12", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPad Air", + "udid": "F78CD721-6DB1-4C19-9601-FEB84D2D0A12", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPad Air 2", - "udid" : "7E3B9E66-5995-4342-929C-43CCFF4E0819", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPad Air 2", + "udid": "7E3B9E66-5995-4342-929C-43CCFF4E0819", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPad Pro (12.9-inch)", - "udid" : "D5483905-8384-4F9A-B337-AE5B7F6B6994", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPad Pro (12.9-inch)", + "udid": "D5483905-8384-4F9A-B337-AE5B7F6B6994", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPad Pro (12.9-inch) (2nd generation)", - "udid" : "DDC7CD7C-8E12-42AF-B39A-DB847CCD84FD", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPad Pro (12.9-inch) (2nd generation)", + "udid": "DDC7CD7C-8E12-42AF-B39A-DB847CCD84FD", + "availabilityError": "runtime profile not found" } ] } diff --git a/test/unit/fixtures/devices-with-unavailable.json b/test/unit/fixtures/devices-with-unavailable.json index c7ff691..21355c7 100644 --- a/test/unit/fixtures/devices-with-unavailable.json +++ b/test/unit/fixtures/devices-with-unavailable.json @@ -1,271 +1,271 @@ { - "devices" : { - "com.apple.CoreSimulator.SimRuntime.tvOS-12-1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV", - "udid" : "FA628127-1D5C-45C3-9918-A47BF7E2AE14", - "availabilityError" : "" + "devices": { + "com.apple.CoreSimulator.SimRuntime.tvOS-12-1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV", + "udid": "FA628127-1D5C-45C3-9918-A47BF7E2AE14", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV 4K", - "udid" : "2EF493BE-E7D5-45E7-9725-8D2706F7220E", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV 4K", + "udid": "2EF493BE-E7D5-45E7-9725-8D2706F7220E", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV 4K (at 1080p)", - "udid" : "FFECD143-B523-4A3D-BA27-1F9706F814CB", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV 4K (at 1080p)", + "udid": "FFECD143-B523-4A3D-BA27-1F9706F814CB", + "availabilityError": "" } ], - "com.apple.CoreSimulator.SimRuntime.iOS-12-1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 5s", - "udid" : "E17597CE-71EE-4402-8B1C-1B526446A3A2", - "availabilityError" : "" + "com.apple.CoreSimulator.SimRuntime.iOS-12-1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 5s", + "udid": "E17597CE-71EE-4402-8B1C-1B526446A3A2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 6", - "udid" : "1C7AB8B9-94C3-4806-86D7-77C13B483902", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 6", + "udid": "1C7AB8B9-94C3-4806-86D7-77C13B483902", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 6 Plus", - "udid" : "EE76EA77-E975-4198-9859-69DFF74252D2", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 6 Plus", + "udid": "EE76EA77-E975-4198-9859-69DFF74252D2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Air", - "udid" : "225C4FDB-5132-423A-9CFF-89D4474395F9", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Air", + "udid": "225C4FDB-5132-423A-9CFF-89D4474395F9", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Air 2", - "udid" : "DDDF281C-F912-471C-B30D-994A2644DF03", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Air 2", + "udid": "DDDF281C-F912-471C-B30D-994A2644DF03", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Pro (12.9-inch)", - "udid" : "1D953CFF-1FBC-413E-B2AB-B4BA4DD5EEC2", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Pro (12.9-inch)", + "udid": "1D953CFF-1FBC-413E-B2AB-B4BA4DD5EEC2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Pro (12.9-inch) (2nd generation)", - "udid" : "A7D1A0D7-D67B-409F-A73D-0DB53EDD860F", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Pro (12.9-inch) (2nd generation)", + "udid": "A7D1A0D7-D67B-409F-A73D-0DB53EDD860F", + "availabilityError": "" } ], - "com.apple.CoreSimulator.SimRuntime.tvOS-12-2" : [ - { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple TV", - "udid" : "84793AD4-E1C9-49EE-B85A-0DCBB0806279", - "availabilityError" : "runtime profile not found" + "com.apple.CoreSimulator.SimRuntime.tvOS-12-2": [ + { + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple TV", + "udid": "84793AD4-E1C9-49EE-B85A-0DCBB0806279", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple TV 4K", - "udid" : "B3ABE34D-7F23-4107-B381-3DD0184134D1", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple TV 4K", + "udid": "B3ABE34D-7F23-4107-B381-3DD0184134D1", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple TV 4K (at 1080p)", - "udid" : "289113A3-52A3-4904-B7B6-E66DF666EDB5", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple TV 4K (at 1080p)", + "udid": "289113A3-52A3-4904-B7B6-E66DF666EDB5", + "availabilityError": "runtime profile not found" } ], - "com.apple.CoreSimulator.SimRuntime.watchOS-5-2" : [ - { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "76D3F91D-5C60-4B9B-A30A-A01A63C6FE73", - "availabilityError" : "runtime profile not found" + "com.apple.CoreSimulator.SimRuntime.watchOS-5-2": [ + { + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 2 - 38mm", + "udid": "76D3F91D-5C60-4B9B-A30A-A01A63C6FE73", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "26B36BEB-A564-4321-A108-72DEEB2D63F9", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 2 - 42mm", + "udid": "26B36BEB-A564-4321-A108-72DEEB2D63F9", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 3 - 38mm", - "udid" : "63D10205-08E3-4A8C-9334-DB0868D87554", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 3 - 38mm", + "udid": "63D10205-08E3-4A8C-9334-DB0868D87554", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 3 - 42mm", - "udid" : "420CD468-9CED-44F7-A8AE-F1FABB18BFB2", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 3 - 42mm", + "udid": "420CD468-9CED-44F7-A8AE-F1FABB18BFB2", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 4 - 40mm", - "udid" : "6E507921-8AE9-4562-93C6-52DFDA87EA40", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 4 - 40mm", + "udid": "6E507921-8AE9-4562-93C6-52DFDA87EA40", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "Apple Watch Series 4 - 44mm", - "udid" : "E5DDFDFA-693A-46A7-B42A-866681E15B83", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "Apple Watch Series 4 - 44mm", + "udid": "E5DDFDFA-693A-46A7-B42A-866681E15B83", + "availabilityError": "runtime profile not found" } ], - "com.apple.CoreSimulator.SimRuntime.watchOS-5-1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "F40113CC-2973-4EBD-87F4-31852A6FF09B", - "availabilityError" : "" + "com.apple.CoreSimulator.SimRuntime.watchOS-5-1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 2 - 38mm", + "udid": "F40113CC-2973-4EBD-87F4-31852A6FF09B", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "5A83C524-FFF6-45AA-936C-365D2F1126F3", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 2 - 42mm", + "udid": "5A83C524-FFF6-45AA-936C-365D2F1126F3", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 3 - 38mm", - "udid" : "C76C585D-96D1-4037-80ED-C73DBBDB3521", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 3 - 38mm", + "udid": "C76C585D-96D1-4037-80ED-C73DBBDB3521", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 3 - 42mm", - "udid" : "DA5E98A8-2D04-474F-A0C3-9A0234F44CC9", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 3 - 42mm", + "udid": "DA5E98A8-2D04-474F-A0C3-9A0234F44CC9", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 4 - 40mm", - "udid" : "DCD321B8-F265-4213-B248-C89AB8B806E1", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 4 - 40mm", + "udid": "DCD321B8-F265-4213-B248-C89AB8B806E1", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 4 - 44mm", - "udid" : "EADBBE94-E97C-4D13-9FF2-44A3524113C7", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 4 - 44mm", + "udid": "EADBBE94-E97C-4D13-9FF2-44A3524113C7", + "availabilityError": "" } ], - "com.apple.CoreSimulator.SimRuntime.iOS-12-2" : [ - { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPhone 5s", - "udid" : "DBC918BB-D519-408D-A5E7-EAD66D875A40", - "availabilityError" : "runtime profile not found" + "com.apple.CoreSimulator.SimRuntime.iOS-12-2": [ + { + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPhone 5s", + "udid": "DBC918BB-D519-408D-A5E7-EAD66D875A40", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPhone 6", - "udid" : "5CC1A69E-75B0-4109-8474-61C605C61493", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPhone 6", + "udid": "5CC1A69E-75B0-4109-8474-61C605C61493", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPhone 6 Plus", - "udid" : "99FE1BB4-66F4-47CA-A144-9198A5CBB9B6", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPhone 6 Plus", + "udid": "99FE1BB4-66F4-47CA-A144-9198A5CBB9B6", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPad Air", - "udid" : "F78CD721-6DB1-4C19-9601-FEB84D2D0A12", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPad Air", + "udid": "F78CD721-6DB1-4C19-9601-FEB84D2D0A12", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPad Air 2", - "udid" : "7E3B9E66-5995-4342-929C-43CCFF4E0819", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPad Air 2", + "udid": "7E3B9E66-5995-4342-929C-43CCFF4E0819", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPad Pro (12.9-inch)", - "udid" : "D5483905-8384-4F9A-B337-AE5B7F6B6994", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPad Pro (12.9-inch)", + "udid": "D5483905-8384-4F9A-B337-AE5B7F6B6994", + "availabilityError": "runtime profile not found" }, { - "availability" : "(unavailable, runtime profile not found)", - "state" : "Shutdown", - "isAvailable" : false, - "name" : "iPad Pro (12.9-inch) (2nd generation)", - "udid" : "DDC7CD7C-8E12-42AF-B39A-DB847CCD84FD", - "availabilityError" : "runtime profile not found" + "availability": "(unavailable, runtime profile not found)", + "state": "Shutdown", + "isAvailable": false, + "name": "iPad Pro (12.9-inch) (2nd generation)", + "udid": "DDC7CD7C-8E12-42AF-B39A-DB847CCD84FD", + "availabilityError": "runtime profile not found" } ] } diff --git a/test/unit/fixtures/devices.json b/test/unit/fixtures/devices.json index 4857966..5823480 100644 --- a/test/unit/fixtures/devices.json +++ b/test/unit/fixtures/devices.json @@ -1,137 +1,137 @@ { - "devices" : { - "com.apple.CoreSimulator.SimRuntime.tvOS-12-1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV", - "udid" : "FA628127-1D5C-45C3-9918-A47BF7E2AE14", - "availabilityError" : "" + "devices": { + "com.apple.CoreSimulator.SimRuntime.tvOS-12-1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV", + "udid": "FA628127-1D5C-45C3-9918-A47BF7E2AE14", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV 4K", - "udid" : "2EF493BE-E7D5-45E7-9725-8D2706F7220E", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV 4K", + "udid": "2EF493BE-E7D5-45E7-9725-8D2706F7220E", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple TV 4K (at 1080p)", - "udid" : "FFECD143-B523-4A3D-BA27-1F9706F814CB", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple TV 4K (at 1080p)", + "udid": "FFECD143-B523-4A3D-BA27-1F9706F814CB", + "availabilityError": "" } ], - "com.apple.CoreSimulator.SimRuntime.iOS-12-1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 5s", - "udid" : "E17597CE-71EE-4402-8B1C-1B526446A3A2", - "availabilityError" : "" + "com.apple.CoreSimulator.SimRuntime.iOS-12-1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 5s", + "udid": "E17597CE-71EE-4402-8B1C-1B526446A3A2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 6", - "udid" : "1C7AB8B9-94C3-4806-86D7-77C13B483902", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 6", + "udid": "1C7AB8B9-94C3-4806-86D7-77C13B483902", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPhone 6 Plus", - "udid" : "EE76EA77-E975-4198-9859-69DFF74252D2", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPhone 6 Plus", + "udid": "EE76EA77-E975-4198-9859-69DFF74252D2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Air", - "udid" : "225C4FDB-5132-423A-9CFF-89D4474395F9", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Air", + "udid": "225C4FDB-5132-423A-9CFF-89D4474395F9", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Air 2", - "udid" : "DDDF281C-F912-471C-B30D-994A2644DF03", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Air 2", + "udid": "DDDF281C-F912-471C-B30D-994A2644DF03", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Pro (12.9-inch)", - "udid" : "1D953CFF-1FBC-413E-B2AB-B4BA4DD5EEC2", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Pro (12.9-inch)", + "udid": "1D953CFF-1FBC-413E-B2AB-B4BA4DD5EEC2", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "iPad Pro (12.9-inch) (2nd generation)", - "udid" : "A7D1A0D7-D67B-409F-A73D-0DB53EDD860F", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "iPad Pro (12.9-inch) (2nd generation)", + "udid": "A7D1A0D7-D67B-409F-A73D-0DB53EDD860F", + "availabilityError": "" } ], - "com.apple.CoreSimulator.SimRuntime.watchOS-5-1" : [ - { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 2 - 38mm", - "udid" : "F40113CC-2973-4EBD-87F4-31852A6FF09B", - "availabilityError" : "" + "com.apple.CoreSimulator.SimRuntime.watchOS-5-1": [ + { + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 2 - 38mm", + "udid": "F40113CC-2973-4EBD-87F4-31852A6FF09B", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 2 - 42mm", - "udid" : "5A83C524-FFF6-45AA-936C-365D2F1126F3", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 2 - 42mm", + "udid": "5A83C524-FFF6-45AA-936C-365D2F1126F3", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 3 - 38mm", - "udid" : "C76C585D-96D1-4037-80ED-C73DBBDB3521", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 3 - 38mm", + "udid": "C76C585D-96D1-4037-80ED-C73DBBDB3521", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 3 - 42mm", - "udid" : "DA5E98A8-2D04-474F-A0C3-9A0234F44CC9", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 3 - 42mm", + "udid": "DA5E98A8-2D04-474F-A0C3-9A0234F44CC9", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 4 - 40mm", - "udid" : "DCD321B8-F265-4213-B248-C89AB8B806E1", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 4 - 40mm", + "udid": "DCD321B8-F265-4213-B248-C89AB8B806E1", + "availabilityError": "" }, { - "availability" : "(available)", - "state" : "Shutdown", - "isAvailable" : true, - "name" : "Apple Watch Series 4 - 44mm", - "udid" : "EADBBE94-E97C-4D13-9FF2-44A3524113C7", - "availabilityError" : "" + "availability": "(available)", + "state": "Shutdown", + "isAvailable": true, + "name": "Apple Watch Series 4 - 44mm", + "udid": "EADBBE94-E97C-4D13-9FF2-44A3524113C7", + "availabilityError": "" } ] } diff --git a/test/unit/simctl-specs.ts b/test/unit/simctl-specs.ts index 9af888b..e4314fb 100644 --- a/test/unit/simctl-specs.ts +++ b/test/unit/simctl-specs.ts @@ -2,14 +2,15 @@ import sinon from 'sinon'; import _ from 'lodash'; import fs from 'node:fs'; import path from 'node:path'; -import { expect, use } from 'chai'; +import {expect, use} from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import { Simctl } from '../../lib/simctl'; +import {Simctl} from '../../lib/simctl'; use(chaiAsPromised); // @ts-ignore - __dirname is available in CommonJS -const testDir = typeof __dirname !== 'undefined' ? __dirname : path.dirname(require.resolve('./simctl-specs.ts')); +const testDir = + typeof __dirname !== 'undefined' ? __dirname : path.dirname(require.resolve('./simctl-specs.ts')); const devicePayloads = [ [ @@ -17,7 +18,10 @@ const devicePayloads = [ stdout: fs.readFileSync(path.join(testDir, 'fixtures/devices.json'), 'utf-8'), }, { - stdout: fs.readFileSync(path.join(__dirname, 'fixtures/devices-with-unavailable.json'), 'utf-8'), + stdout: fs.readFileSync( + path.join(__dirname, 'fixtures/devices-with-unavailable.json'), + 'utf-8', + ), }, ], [ @@ -25,7 +29,10 @@ const devicePayloads = [ stdout: fs.readFileSync(path.join(__dirname, 'fixtures/devices-simple.json'), 'utf-8'), }, { - stdout: fs.readFileSync(path.join(__dirname, 'fixtures/devices-with-unavailable-simple.json'), 'utf-8'), + stdout: fs.readFileSync( + path.join(__dirname, 'fixtures/devices-with-unavailable-simple.json'), + 'utf-8', + ), }, ], ]; @@ -33,18 +40,17 @@ const devicePayloads = [ describe('simctl', function () { let execStub: sinon.SinonStub; - function stubSimctl (xcrun: { path?: string | null } = {}) { - const simctl = new Simctl({ xcrun: { path: xcrun.path ?? null } }); - execStub = sinon.stub(simctl, 'exec' as any).resolves({ stdout: '', stderr: '' }); + function stubSimctl(xcrun: {path?: string | null} = {}) { + const simctl = new Simctl({xcrun: {path: xcrun.path ?? null}}); + execStub = sinon.stub(simctl, 'exec' as any).resolves({stdout: '', stderr: ''}); return simctl; } - describe('getDevices', function () { let simctl: Simctl; beforeEach(function () { - simctl = stubSimctl({ path: 'xcrun' }); + simctl = stubSimctl({path: 'xcrun'}); }); afterEach(function () { if (execStub) { @@ -140,7 +146,7 @@ describe('simctl', function () { let simctl: Simctl; beforeEach(function () { - simctl = stubSimctl({ path: 'xcrun' }); + simctl = stubSimctl({path: 'xcrun'}); }); afterEach(function () { if (execStub) { @@ -156,21 +162,25 @@ describe('simctl', function () { it('should create iOS simulator using xcrun path from env', async function () { process.env.XCRUN_BINARY = 'some/path'; - simctl = stubSimctl({ path: undefined }); - execStub.onCall(0).returns({stdout: 'not json'}) - .onCall(1).returns({stdout: '12.1.1', stderr: ''}) - .onCall(2).returns({stdout: 'EE76EA77-E975-4198-9859-69DFF74252D2', stderr: ''}) - .onCall(3).returns(devicesPayload); - - const devices = await simctl.createDevice( - 'name', - 'iPhone 6 Plus', - '12.1.1', - { timeout: 20000 } - ); + simctl = stubSimctl({path: undefined}); + execStub + .onCall(0) + .returns({stdout: 'not json'}) + .onCall(1) + .returns({stdout: '12.1.1', stderr: ''}) + .onCall(2) + .returns({stdout: 'EE76EA77-E975-4198-9859-69DFF74252D2', stderr: ''}) + .onCall(3) + .returns(devicesPayload); + + const devices = await simctl.createDevice('name', 'iPhone 6 Plus', '12.1.1', { + timeout: 20000, + }); expect(execStub.getCall(2).args[0]).to.eql('create'); expect(execStub.getCall(2).args[1].args).to.eql([ - 'name', 'iPhone 6 Plus', 'com.apple.CoreSimulator.SimRuntime.iOS-12-1' + 'name', + 'iPhone 6 Plus', + 'com.apple.CoreSimulator.SimRuntime.iOS-12-1', ]); expect(execStub.getCall(0).args[0]).to.eql('list'); expect(devices).to.eql('EE76EA77-E975-4198-9859-69DFF74252D2'); @@ -178,21 +188,25 @@ describe('simctl', function () { it('should create iOS simulator using xcrun path from passed opts', async function () { process.env.XCRUN_BINARY = 'some/path'; - simctl = stubSimctl({ path: 'other/path' }); - execStub.onCall(0).returns({stdout: 'not json'}) - .onCall(1).returns({stdout: '12.1.1', stderr: ''}) - .onCall(2).returns({stdout: 'EE76EA77-E975-4198-9859-69DFF74252D2', stderr: ''}) - .onCall(3).returns(devicesPayload); - - const devices = await simctl.createDevice( - 'name', - 'iPhone 6 Plus', - '12.1.1', - { timeout: 20000 } - ); + simctl = stubSimctl({path: 'other/path'}); + execStub + .onCall(0) + .returns({stdout: 'not json'}) + .onCall(1) + .returns({stdout: '12.1.1', stderr: ''}) + .onCall(2) + .returns({stdout: 'EE76EA77-E975-4198-9859-69DFF74252D2', stderr: ''}) + .onCall(3) + .returns(devicesPayload); + + const devices = await simctl.createDevice('name', 'iPhone 6 Plus', '12.1.1', { + timeout: 20000, + }); expect(execStub.getCall(2).args[0]).to.eql('create'); expect(execStub.getCall(2).args[1].args).to.eql([ - 'name', 'iPhone 6 Plus', 'com.apple.CoreSimulator.SimRuntime.iOS-12-1' + 'name', + 'iPhone 6 Plus', + 'com.apple.CoreSimulator.SimRuntime.iOS-12-1', ]); expect(execStub.getCall(0).args[0]).to.eql('list'); expect(devices).to.eql('EE76EA77-E975-4198-9859-69DFF74252D2'); @@ -224,101 +238,111 @@ describe('simctl', function () { } ] }`; - execStub.onCall(0).returns({stdout: runtimesJson}) - .onCall(1).returns({stdout: 'FA628127-1D5C-45C3-9918-A47BF7E2AE14', stderr: ''}) - .onCall(2).returns(devicesPayload); - - const devices = await simctl.createDevice( - 'name', - 'iPhone 6 Plus', - '12.1.1', - { timeout: 20000 } - ); + execStub + .onCall(0) + .returns({stdout: runtimesJson}) + .onCall(1) + .returns({stdout: 'FA628127-1D5C-45C3-9918-A47BF7E2AE14', stderr: ''}) + .onCall(2) + .returns(devicesPayload); + + const devices = await simctl.createDevice('name', 'iPhone 6 Plus', '12.1.1', { + timeout: 20000, + }); expect(execStub.getCall(1).args[0]).to.eql('create'); expect(execStub.getCall(1).args[1].args).to.eql([ - 'name', 'iPhone 6 Plus', 'com.apple.CoreSimulator.SimRuntime.iOS-12-1-1' + 'name', + 'iPhone 6 Plus', + 'com.apple.CoreSimulator.SimRuntime.iOS-12-1-1', ]); expect(devices).to.eql('FA628127-1D5C-45C3-9918-A47BF7E2AE14'); }); it('should create tvOS simulator', async function () { - execStub.onCall(0).returns({stdout: 'invalid json'}) - .onCall(1).returns({stdout: 'com.apple.CoreSimulator.SimRuntime.tvOS-12-1', stderr: ''}) - .onCall(2).returns({stdout: 'FA628127-1D5C-45C3-9918-A47BF7E2AE14', stderr: ''}) - .onCall(3).returns(devicesPayload); - - const devices = await simctl.createDevice( - 'name', - 'Apple TV', - '12.1', - { timeout: 20000, platform: 'tvOS' } - ); + execStub + .onCall(0) + .returns({stdout: 'invalid json'}) + .onCall(1) + .returns({stdout: 'com.apple.CoreSimulator.SimRuntime.tvOS-12-1', stderr: ''}) + .onCall(2) + .returns({stdout: 'FA628127-1D5C-45C3-9918-A47BF7E2AE14', stderr: ''}) + .onCall(3) + .returns(devicesPayload); + + const devices = await simctl.createDevice('name', 'Apple TV', '12.1', { + timeout: 20000, + platform: 'tvOS', + }); expect(execStub.getCall(2).args[0]).to.eql('create'); expect(execStub.getCall(2).args[1].args).to.eql([ - 'name', 'Apple TV', 'com.apple.CoreSimulator.SimRuntime.tvOS-12-1' + 'name', + 'Apple TV', + 'com.apple.CoreSimulator.SimRuntime.tvOS-12-1', ]); expect(devices).to.eql('FA628127-1D5C-45C3-9918-A47BF7E2AE14'); }); it('should create iOS simulator with old runtime format', async function () { - execStub.onCall(0).returns({stdout: 'invalid json'}) - .onCall(1).returns({stdout: '12.1', stderr: ''}) - .onCall(2).throws('Invalid runtime: com.apple.CoreSimulator.SimRuntime.iOS-12-1') - .onCall(3).returns({stdout: 'EE76EA77-E975-4198-9859-69DFF74252D2', stderr: ''}) - .onCall(4).returns(devicesPayload); - - const devices = await simctl.createDevice( - 'name', - 'iPhone 6 Plus', - '12.1', - { timeout: 20000 } - ); + execStub + .onCall(0) + .returns({stdout: 'invalid json'}) + .onCall(1) + .returns({stdout: '12.1', stderr: ''}) + .onCall(2) + .throws('Invalid runtime: com.apple.CoreSimulator.SimRuntime.iOS-12-1') + .onCall(3) + .returns({stdout: 'EE76EA77-E975-4198-9859-69DFF74252D2', stderr: ''}) + .onCall(4) + .returns(devicesPayload); + + const devices = await simctl.createDevice('name', 'iPhone 6 Plus', '12.1', {timeout: 20000}); expect(execStub.getCall(3).args[0]).to.eql('create'); - expect(execStub.getCall(3).args[1].args).to.eql([ - 'name', 'iPhone 6 Plus', '12.1' - ]); + expect(execStub.getCall(3).args[1].args).to.eql(['name', 'iPhone 6 Plus', '12.1']); expect(devices).to.eql('EE76EA77-E975-4198-9859-69DFF74252D2'); }); it('should create iOS simulator with old runtime format and three-part platform version', async function () { - execStub.onCall(0).returns({stdout: 'invalid json'}) - .onCall(1).returns({stdout: '12.1.1', stderr: ''}) - .onCall(2).throws('Invalid runtime: com.apple.CoreSimulator.SimRuntime.iOS-12-1') - .onCall(3).returns({stdout: 'EE76EA77-E975-4198-9859-69DFF74252D2', stderr: ''}) - .onCall(4).returns(devicesPayload); - - const devices = await simctl.createDevice( - 'name', - 'iPhone 6 Plus', - '12.1', - { timeout: 20000 } - ); + execStub + .onCall(0) + .returns({stdout: 'invalid json'}) + .onCall(1) + .returns({stdout: '12.1.1', stderr: ''}) + .onCall(2) + .throws('Invalid runtime: com.apple.CoreSimulator.SimRuntime.iOS-12-1') + .onCall(3) + .returns({stdout: 'EE76EA77-E975-4198-9859-69DFF74252D2', stderr: ''}) + .onCall(4) + .returns(devicesPayload); + + const devices = await simctl.createDevice('name', 'iPhone 6 Plus', '12.1', {timeout: 20000}); expect(execStub.getCall(3).args[0]).to.eql('create'); - expect(execStub.getCall(3).args[1].args).to.eql([ - 'name', 'iPhone 6 Plus', '12.1' - ]); + expect(execStub.getCall(3).args[1].args).to.eql(['name', 'iPhone 6 Plus', '12.1']); expect(devices).to.eql('EE76EA77-E975-4198-9859-69DFF74252D2'); }); it('should create iOS simulator with three-part platform version and three-part runtime', async function () { - execStub.onCall(0).returns({stdout: 'invalid json'}) - .onCall(1).returns({stdout: '12.1.1', stderr: ''}) - .onCall(2).throws('Invalid runtime: com.apple.CoreSimulator.SimRuntime.iOS-12-1') - .onCall(3).returns({stdout: 'EE76EA77-E975-4198-9859-69DFF74252D2', stderr: ''}) - .onCall(4).returns(devicesPayload); - - const devices = await simctl.createDevice( - 'name', - 'iPhone 6 Plus', - '12.1.1', - { timeout: 20000 } - ); + execStub + .onCall(0) + .returns({stdout: 'invalid json'}) + .onCall(1) + .returns({stdout: '12.1.1', stderr: ''}) + .onCall(2) + .throws('Invalid runtime: com.apple.CoreSimulator.SimRuntime.iOS-12-1') + .onCall(3) + .returns({stdout: 'EE76EA77-E975-4198-9859-69DFF74252D2', stderr: ''}) + .onCall(4) + .returns(devicesPayload); + + const devices = await simctl.createDevice('name', 'iPhone 6 Plus', '12.1.1', { + timeout: 20000, + }); expect(execStub.getCall(3).args[0]).to.eql('create'); expect(execStub.getCall(3).args[1].args).to.eql([ - 'name', 'iPhone 6 Plus', 'com.apple.CoreSimulator.SimRuntime.iOS-12-1-1' + 'name', + 'iPhone 6 Plus', + 'com.apple.CoreSimulator.SimRuntime.iOS-12-1-1', ]); expect(devices).to.eql('EE76EA77-E975-4198-9859-69DFF74252D2'); }); }); }); -