-
-
Notifications
You must be signed in to change notification settings - Fork 423
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add mobile:simctl to run listed simctl subcommands (#2461)
* add simctl command * add rough description * remove timeout * update example * add result * add a note * add test * fix lint and update types * tweak the readme * check the given command target * tweak the example * add tests * add simulator check * tweak docs * revert bad commit * add timeout as an option * add tests * bump node-simctl * tweak type * exclude addmedia
- Loading branch information
Showing
7 changed files
with
182 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { errors } from 'appium/driver'; | ||
|
||
/** | ||
* List of subcommands for `simctl` we provide as mobile simctl command. | ||
* They accept 'device' target. | ||
*/ | ||
const SUBCOMMANDS_HAS_DEVICE = [ | ||
'boot', | ||
'get_app_container', | ||
'getenv', | ||
'icloud_sync', | ||
'install', | ||
'install_app_data', | ||
'io', | ||
'keychain', | ||
'launch', | ||
'location', | ||
'logverbose', | ||
'openurl', | ||
'pbcopy', | ||
'pbpaste', | ||
'privacy', | ||
'push', | ||
'shutdown', | ||
'spawn', | ||
'status_bar', | ||
'terminate', | ||
'ui', | ||
'uninstall' | ||
]; | ||
|
||
const commands = { | ||
/** | ||
* Run the given command with arguments as `xcrun simctl` subcommand. | ||
* This method works behind the 'simctl' security flag. | ||
* @this {XCUITestDriver} | ||
* @param {string} command Subcommand to run with `xcrun simctl` | ||
* @param {string[]} [args=[]] arguments for the subcommand. The arguments should be after <device> in the help. | ||
* @param {number|undefined} timeout - The maximum number of milliseconds | ||
* @returns {Promise<SimctlExecResponse>} | ||
* @throws {Error} If the simctl subcommand command returns non-zero return code, or the given subcommand was invalid. | ||
*/ | ||
async mobileSimctl(command, args = [], timeout = undefined) { | ||
if (!this.isSimulator()) { | ||
throw new errors.UnsupportedOperationError(`Only simulator is supported.`); | ||
}; | ||
|
||
if (!this.opts.udid) { | ||
throw new errors.InvalidArgumentError(`Unknown device or simulator UDID: '${this.opts.udid}'`); | ||
} | ||
|
||
if (!SUBCOMMANDS_HAS_DEVICE.includes(command)) { | ||
throw new errors.InvalidArgumentError(`The given command '${command}' is not supported. ` + | ||
`Available subcommands are ${SUBCOMMANDS_HAS_DEVICE.join(',')}`); | ||
} | ||
|
||
return await /** @type {import('./../driver').Simulator} */ (this.device).simctl.exec( | ||
command, | ||
{args: [this.opts.udid, ...args], timeout} | ||
); | ||
} | ||
}; | ||
|
||
export default {...commands}; | ||
|
||
/** | ||
* @typedef {Object} SimctlExecResponse | ||
* @property {string} stdout The output of standard out. | ||
* @property {string} stderr The output of standard error. | ||
* @property {number} code Return code. | ||
*/ | ||
|
||
/** | ||
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import sinon from 'sinon'; | ||
import XCUITestDriver from '../../../lib/driver'; | ||
import Simctl from 'node-simctl'; | ||
|
||
|
||
describe('general commands', function () { | ||
const driver = new XCUITestDriver(); | ||
const simctl = new Simctl(); | ||
driver._device = { simctl }; | ||
|
||
let chai; | ||
let mockSimctl; | ||
|
||
before(async function () { | ||
chai = await import('chai'); | ||
chai.should(); | ||
}); | ||
|
||
beforeEach(function () { | ||
mockSimctl = sinon.mock(driver.device.simctl); | ||
}); | ||
|
||
afterEach(function () { | ||
mockSimctl.verify(); | ||
}); | ||
|
||
describe('simctl', function () { | ||
it('should call xcrun simctl', async function () { | ||
driver.opts.udid = '60EB8FDB-92E0-4895-B466-0153C6DE7BAE'; | ||
driver.isSimulator = () => true; | ||
mockSimctl.expects('exec').once().withExactArgs( | ||
'getenv', | ||
{args: ['60EB8FDB-92E0-4895-B466-0153C6DE7BAE', 'HOME'], timeout: undefined} | ||
); | ||
await driver.mobileSimctl('getenv', ['HOME']); | ||
}); | ||
|
||
it('should call xcrun simctl with timeout', async function () { | ||
driver.opts.udid = '60EB8FDB-92E0-4895-B466-0153C6DE7BAE'; | ||
driver.isSimulator = () => true; | ||
mockSimctl.expects('exec').once().withExactArgs( | ||
'getenv', | ||
{args: ['60EB8FDB-92E0-4895-B466-0153C6DE7BAE', 'HOME'], timeout: 10000} | ||
); | ||
await driver.mobileSimctl('getenv', ['HOME'], 10000); | ||
}); | ||
|
||
it('should raise an error as not supported command', async function () { | ||
driver.opts.udid = '60EB8FDB-92E0-4895-B466-0153C6DE7BAE'; | ||
driver.isSimulator = () => true; | ||
mockSimctl.expects('exec').never(); | ||
await driver.mobileSimctl( | ||
'list', | ||
['devices', 'booted', '--json'] | ||
).should.eventually.be.rejected; | ||
}); | ||
|
||
it('should raise an error as no udid', async function () { | ||
driver.opts.udid = null; | ||
driver.isSimulator = () => true; | ||
mockSimctl.expects('exec').never(); | ||
await driver.mobileSimctl( | ||
'getenv', ['HOME'] | ||
).should.eventually.be.rejected; | ||
}); | ||
|
||
it('should raise an error for non-simulator', async function () { | ||
driver.opts.udid = '60EB8FDB-92E0-4895-B466-0153C6DE7BAE'; | ||
driver.isSimulator = () => false; | ||
mockSimctl.expects('exec').never(); | ||
await driver.mobileSimctl( | ||
'getenv', ['HOME'] | ||
).should.eventually.be.rejected; | ||
}); | ||
}); | ||
}); |