Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add setting geolocation by set-simulator-location as the first method #249

Merged
merged 9 commits into from
Dec 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions lib/geolocation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import _ from 'lodash';
import log from './logger';
import { exec } from 'teen_process';
import { fs } from 'appium-support';

const LYFT_SET_LOCATION = 'set-simulator-location';

/**
* Set custom geolocation parameters for the given Simulator using LYFT_SET_LOCATION.
*
* @param {string} udid - The udid to set the given geolocation
* @param {string|number} latitude - The latitude value, which is going to be entered
* into the corresponding edit field, for example '39,0006'.
* @param {string|number} longitude - The longitude value, which is going to be entered
* into the corresponding edit field, for example '19,0068'.
* @throws {Error} If it failed to set the location
*/
async function setLocationWithLyft (udid, latitude, longitude) {
try {
await fs.which(LYFT_SET_LOCATION);
} catch (e) {
throw new Error(`'${LYFT_SET_LOCATION}' binary has not been found in your PATH. ` +
'Please install it as "brew install lyft/formulae/set-simulator-location" by brew or ' +
'read https://github.com/lyft/set-simulator-location to set the binary by manual to ' +
'be able to set geolocation by the library.');
}

try {
await exec(LYFT_SET_LOCATION, [
'-c', latitude, longitude,
'-u', udid
]);
} catch (e) {
throw new Error(`Failed to set geolocation with '${LYFT_SET_LOCATION}'. ` +
`Original error: ${e.stderr || e.message}`);
}
}

/**
* Set custom geolocation parameters for the given Simulator using idb.
*
* @param {Object} idb - The IDB instance
* @param {string|number} latitude - The latitude value, which is going to be entered
* into the corresponding edit field, for example '39,0006'.
* @param {string|number} longitude - The longitude value, which is going to be entered
* into the corresponding edit field, for example '19,0068'.
* @throws {Error} If it failed to set the location
*/
async function setLocationWithIdb (idb, latitude, longitude) {
if (idb) {
try {
await idb.setLocation(latitude, longitude);
} catch (e) {
throw new Error(`Failed to set geolocation with idb. Original error: ${e.stderr || e.message}`);
}
}
throw new Error('Failed to set geolocation with idb because it is not installed');
}


/**
* Set custom geolocation parameters for the given Simulator using AppleScript
*
* @param {Object} sim - The SimulatorXcode object
* @param {string|number} latitude - The latitude value, which is going to be entered
* into the corresponding edit field, for example '39,0006'.
* @param {string|number} longitude - The longitude value, which is going to be entered
* into the corresponding edit field, for example '19,0068'.
* @throws {Error} If it failed to set the location
*/
async function setLocationWithAppleScript (sim, latitude, longitude) {
const output = await sim.executeUIClientScript(`
tell application "System Events"
tell process "Simulator"
set featureName to "Custom Location"
set dstMenuItem to menu item (featureName & "…") of menu 1 of menu item "Location" of menu 1 of menu bar item "Debug" of menu bar 1
click dstMenuItem
delay 1
set value of text field 1 of window featureName to ${latitude} as string
delay 0.5
set value of text field 2 of window featureName to ${longitude} as string
delay 0.5
click button "OK" of window featureName
delay 0.5
set isInvisible to (not (exists (window featureName)))
end tell
end tell
`);
log.debug(`Geolocation parameters dialog accepted: ${output}`);
if (_.trim(output) !== 'true') {
throw new Error(`Failed to set geolocation with AppleScript. Original error: ${output}`);
}
}

export {
setLocationWithLyft, setLocationWithIdb, setLocationWithAppleScript
};
43 changes: 20 additions & 23 deletions lib/simulator-xcode-8.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { waitForCondition } from 'asyncbox';
import { exec } from 'teen_process';
import { getAppContainer, openUrl as simctlOpenUrl, terminate,
appInfo, spawn, startBootMonitor } from 'node-simctl';
import {
setLocationWithLyft,
setLocationWithIdb,
setLocationWithAppleScript } from './geolocation';

// these sims are sloooooooow
const STARTUP_TIMEOUT = 120 * 1000;
Expand Down Expand Up @@ -282,30 +286,23 @@ class SimulatorXcode8 extends SimulatorXcode7 {
* @throws {Error} If there was an error while setting the location
*/
async setGeolocation (latitude, longitude) {
if (this.idb) {
await this.idb.setLocation(latitude, longitude);
return true;
const locationSetters = [
async () => await setLocationWithLyft(this.udid, latitude, longitude),
async () => await setLocationWithIdb(this.idb, latitude, longitude),
async () => await setLocationWithAppleScript(this, latitude, longitude)
];

let lastError;
for (const setter of locationSetters) {
try {
await setter();
return true;
} catch (e) {
log.info(e.message);
lastError = e;
}
}
log.warn(`Cannot set geolocation with idb, because it is not installed. Defaulting to AppleScript`);
const output = await this.executeUIClientScript(`
tell application "System Events"
tell process "Simulator"
set featureName to "Custom Location"
set dstMenuItem to menu item (featureName & "…") of menu 1 of menu item "Location" of menu 1 of menu bar item "Debug" of menu bar 1
click dstMenuItem
delay 1
set value of text field 1 of window featureName to ${latitude} as string
delay 0.5
set value of text field 2 of window featureName to ${longitude} as string
delay 0.5
click button "OK" of window featureName
delay 0.5
set isInvisible to (not (exists (window featureName)))
end tell
end tell
`);
log.debug(`Geolocation parameters dialog accepted: ${output}`);
return _.isString(output) && output.trim() === 'true';
throw lastError;
}
}

Expand Down