-
-
Notifications
You must be signed in to change notification settings - Fork 425
/
Copy pathlocation.js
133 lines (120 loc) · 5.23 KB
/
location.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import {services} from 'appium-ios-device';
import {errors} from 'appium/driver';
import {util} from 'appium/support';
import {AuthorizationStatus} from './enum';
import { isIos17OrNewer } from '../utils';
export default {
/**
* Returns location of the device under test.
* The device under test must allow the location services for WDA
* as 'Always' to get the location data correctly.
*
* The 'latitude', 'longitude' and 'altitude' could be zero even
* if the Location Services are set to 'Always', because the device
* needs some time to update the location data.
*
* For iOS 17, the return value could be the result of
* "mobile:getSimulatedLocation" if the simulated location has been previously set
* "mobile:setSimulatedLocation" already.
*
* @returns {Promise<import('./types').LocationWithAltitude>}
* @throws {Error} If the device under test returns an error message.
* i.e.: tvOS returns unsupported error
* @this {XCUITestDriver}
*/
async getGeoLocation() {
// Currently we proxy the setGeoLocation to mobile:setSimulatedLocation for iOS 17+.
// It would be helpful to address to use "mobile:getSimulatedLocation" for iOS 17+.
if (isIos17OrNewer(this.opts)) {
const {latitude, longitude} = await this.mobileGetSimulatedLocation();
if (latitude && longitude) {
this.log.debug('Returning the geolocation that has been previously set by mobile:setSimulatedLocation. ' +
'mobile:resetSimulatedLocation can reset the location configuration.');
return {latitude, longitude, altitude: 0};
}
this.log.warn(`No location was set by mobile:setSimulatedLocation. Trying to return the location from the device.`);
}
// Please do not change the way to get the location here with '/wda/simulatedLocation'
// endpoint because they could return different value before setting the simulated location.
// '/wda/device/location' returns current device location information,
// but '/wda/simulatedLocation' returns `null` values until the WDA process
// sets a simulated location. After setting the value, both returns the same values.
const {authorizationStatus, latitude, longitude, altitude} = /** @type {WDALocationInfo} */ (
await this.proxyCommand('/wda/device/location', 'GET')
);
// '3' is 'Always' in the privacy
// https://developer.apple.com/documentation/corelocation/clauthorizationstatus
if (authorizationStatus !== AuthorizationStatus.authorizedAlways) {
throw this.log.errorWithException(
`Location service must be set to 'Always' in order to ` +
`retrieve the current geolocation data. Please set it up manually via ` +
`'Settings > Privacy > Location Services -> WebDriverAgentRunner-Runner'. ` +
`Or please use 'mobile:getSimulatedLocation'/'mobile:setSimulatedLocation' commands ` +
`to simulate locations instead.`,
);
}
return {latitude, longitude, altitude};
},
/**
* Set location of the device under test.
*
* iOS 17+ real device environment will be via "mobile:setSimulatedLocation" as
* setting simulated location for XCTest session.
*
* @param {Partial<Location>} location
* @this {XCUITestDriver}
*/
async setGeoLocation(location) {
let {latitude, longitude} = location;
if (!util.hasValue(latitude) || !util.hasValue(longitude)) {
throw new errors.InvalidArgumentError(`Both latitude and longitude should be set`);
}
if (this.isSimulator()) {
await /** @type {import('../driver').Simulator} */ (this.device).setGeolocation(`${latitude}`, `${longitude}`);
return /** @type {Location} */ ({latitude, longitude, altitude: 0});
}
if (isIos17OrNewer(this.opts)) {
this.log.info(`Proxying to mobile:setSimulatedLocation method for iOS 17+ platform version`);
await this.mobileSetSimulatedLocation(latitude, longitude);
} else {
const service = await services.startSimulateLocationService(this.opts.udid);
try {
service.setLocation(latitude, longitude);
} catch (e) {
throw this.log.errorWithException(
`Can't set the location on device '${this.opts.udid}'. Original error: ${e.message}`,
);
} finally {
service.close();
}
}
return /** @type {Location} */ ({latitude, longitude, altitude: 0});
},
/**
* Reset the location service on real device.
* Raises not implemented error for simulator.
* @throws {Error} If the device is simulator, or 'resetLocation' raises an error.
* @this {XCUITestDriver}
*/
async mobileResetLocationService() {
if (this.isSimulator()) {
throw new errors.NotImplementedError();
}
const service = await services.startSimulateLocationService(this.opts.udid);
try {
service.resetLocation();
} catch (err) {
throw this.log.errorWithException(
`Failed to reset the location on the device on device '${this.opts.udid}'. ` +
`Origianl error: ${err.message}`,
);
} finally {
service.close();
}
},
};
/**
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver
* @typedef {import('./types').WDALocationInfo} WDALocationInfo
* @typedef {import('@appium/types').Location} Location
*/