2016-03-15 18:21:34 -06:00
/ *
*
* Licensed to the Apache Software Foundation ( ASF ) under one
* or more contributor license agreements . See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership . The ASF licenses this file
* to you under the Apache License , Version 2.0 ( the
* "License" ) ; you may not use this file except in compliance
* with the License . You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing ,
* software distributed under the License is distributed on an
* "AS IS" BASIS , WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND , either express or implied . See the License for the
* specific language governing permissions and limitations
* under the License .
*
* /
2016-04-12 17:33:37 -06:00
/* jshint jasmine: true */
/* global WinJS, device */
2016-03-15 18:21:34 -06:00
exports . defineAutoTests = function ( ) {
var fail = function ( done , context , message ) {
// prevents done() to be called several times
if ( context ) {
if ( context . done ) return ;
context . done = true ;
}
if ( message ) {
expect ( false ) . toBe ( true , message ) ;
} else {
expect ( false ) . toBe ( true ) ;
}
// watchPosition could call its callback sync (before returning the value)
// so we invoke done async to make sure we know watcher id to .clear in afterEach
setTimeout ( function ( ) {
done ( ) ;
} ) ;
} ;
var succeed = function ( done , context ) {
// prevents done() to be called several times
if ( context ) {
if ( context . done ) return ;
context . done = true ;
}
expect ( true ) . toBe ( true ) ;
// watchPosition could call its callback sync (before returning the value)
// so we invoke done async to make sure we know watcher id to .clear in afterEach
setTimeout ( function ( ) {
done ( ) ;
} ) ;
} ;
// On Windows, some tests prompt user for permission to use geolocation and interrupt autotests run
var isWindowsStore = ( cordova . platformId == "windows8" ) || ( cordova . platformId == "windows" && ! WinJS . Utilities . isPhone ) ;
var majorDeviceVersion = null ;
var versionRegex = /(\d)\..+/ . exec ( device . version ) ;
if ( versionRegex !== null ) {
majorDeviceVersion = Number ( versionRegex [ 1 ] ) ;
}
// Starting from Android 6.0 there are confirmation dialog which prevents us from running auto tests in silent mode (user interaction needed)
// Also, Android emulator doesn't provide geo fix without manual interactions or mocks
var skipAndroid = cordova . platformId == "android" && ( device . isVirtual || majorDeviceVersion >= 6 ) ;
var isIOSSim = false ; // if iOS simulator does not have a location set, it will fail.
describe ( 'Geolocation (navigator.geolocation)' , function ( ) {
it ( "geolocation.spec.1 should exist" , function ( ) {
expect ( navigator . geolocation ) . toBeDefined ( ) ;
} ) ;
it ( "geolocation.spec.2 should contain a getCurrentPosition function" , function ( ) {
expect ( typeof navigator . geolocation . getCurrentPosition ) . toBeDefined ( ) ;
expect ( typeof navigator . geolocation . getCurrentPosition == 'function' ) . toBe ( true ) ;
} ) ;
it ( "geolocation.spec.3 should contain a watchPosition function" , function ( ) {
expect ( typeof navigator . geolocation . watchPosition ) . toBeDefined ( ) ;
expect ( typeof navigator . geolocation . watchPosition == 'function' ) . toBe ( true ) ;
} ) ;
it ( "geolocation.spec.4 should contain a clearWatch function" , function ( ) {
expect ( typeof navigator . geolocation . clearWatch ) . toBeDefined ( ) ;
expect ( typeof navigator . geolocation . clearWatch == 'function' ) . toBe ( true ) ;
} ) ;
} ) ;
describe ( 'getCurrentPosition method' , function ( ) {
describe ( 'error callback' , function ( ) {
it ( "geolocation.spec.5 should be called if we set timeout to 0 and maximumAge to a very small number" , function ( done ) {
if ( isWindowsStore || skipAndroid ) {
pending ( ) ;
}
navigator . geolocation . getCurrentPosition (
fail . bind ( null , done ) ,
succeed . bind ( null , done ) ,
{
maximumAge : 0 ,
timeout : 0
} ) ;
} ) ;
it ( "geolocation.spec.9 on failure should return PositionError object with error code constants" , function ( done ) {
if ( isWindowsStore || skipAndroid ) {
pending ( ) ;
}
navigator . geolocation . getCurrentPosition (
fail . bind ( this , done ) ,
function ( gpsError ) {
// W3C specs: http://dev.w3.org/geo/api/spec-source.html#position_error_interface
expect ( gpsError . PERMISSION _DENIED ) . toBe ( 1 ) ;
expect ( gpsError . POSITION _UNAVAILABLE ) . toBe ( 2 ) ;
expect ( gpsError . TIMEOUT ) . toBe ( 3 ) ;
done ( ) ;
} ,
{
maximumAge : 0 ,
timeout : 0
} ) ;
} ) ;
} ) ;
describe ( 'success callback' , function ( ) {
it ( "geolocation.spec.6 should be called with a Position object" , function ( done ) {
if ( isWindowsStore || skipAndroid ) {
pending ( ) ;
}
navigator . geolocation . getCurrentPosition ( function ( p ) {
expect ( p . coords ) . toBeDefined ( ) ;
expect ( p . timestamp ) . toBeDefined ( ) ;
done ( ) ;
} , function ( err ) {
if ( err . message && err . message . indexOf ( 'kCLErrorDomain' ) > - 1 ) {
console . log ( "Error: Location not set in simulator, tests will fail." ) ;
expect ( true ) . toBe ( true ) ;
isIOSSim = true ;
done ( ) ;
}
else {
fail ( done ) ;
}
} ,
{
maximumAge : ( 5 * 60 * 1000 ) // 5 minutes maximum age of cached position
} ) ;
} , 25000 ) ; // first geolocation call can take several seconds on some devices
} ) ;
} ) ;
describe ( 'watchPosition method' , function ( ) {
beforeEach ( function ( done ) {
// This timeout is set to lessen the load on platform's geolocation services
// which were causing occasional test failures
setTimeout ( function ( ) {
done ( ) ;
} , 100 ) ;
} ) ;
describe ( 'error callback' , function ( ) {
var errorWatch = null ;
afterEach ( function ( ) {
navigator . geolocation . clearWatch ( errorWatch ) ;
} ) ;
it ( "geolocation.spec.7 should be called if we set timeout to 0 and maximumAge to a very small number" , function ( done ) {
if ( isWindowsStore || skipAndroid ) {
pending ( ) ;
}
var context = this ;
errorWatch = navigator . geolocation . watchPosition (
fail . bind ( null , done , context , 'Unexpected win' ) ,
succeed . bind ( null , done , context ) ,
{
maximumAge : 0 ,
timeout : 0
} ) ;
} ) ;
it ( "geolocation.spec.10 on failure should return PositionError object with error code constants" , function ( done ) {
if ( isWindowsStore || skipAndroid ) {
pending ( ) ;
}
var context = this ;
errorWatch = navigator . geolocation . watchPosition (
fail . bind ( this , done , context , 'Unexpected win' ) ,
function ( gpsError ) {
if ( context . done ) return ;
context . done = true ;
// W3C specs: http://dev.w3.org/geo/api/spec-source.html#position_error_interface
expect ( gpsError . PERMISSION _DENIED ) . toBe ( 1 ) ;
expect ( gpsError . POSITION _UNAVAILABLE ) . toBe ( 2 ) ;
expect ( gpsError . TIMEOUT ) . toBe ( 3 ) ;
done ( ) ;
} ,
{
maximumAge : 0 ,
timeout : 0
} ) ;
} ) ;
} ) ;
describe ( 'success callback' , function ( ) {
var successWatch = null ;
afterEach ( function ( ) {
navigator . geolocation . clearWatch ( successWatch ) ;
} ) ;
it ( "geolocation.spec.8 should be called with a Position object" , function ( done ) {
if ( isWindowsStore || skipAndroid || isIOSSim ) {
pending ( ) ;
}
var context = this ;
successWatch = navigator . geolocation . watchPosition (
function ( p ) {
// prevents done() to be called several times
if ( context . done ) return ;
context . done = true ;
expect ( p . coords ) . toBeDefined ( ) ;
expect ( p . timestamp ) . toBeDefined ( ) ;
// callback could be called sync so we invoke done async to make sure we know watcher id to .clear in afterEach
setTimeout ( function ( ) {
done ( ) ;
} ) ;
} ,
fail . bind ( null , done , context , 'Unexpected fail callback' ) ,
{
maximumAge : ( 5 * 60 * 1000 ) // 5 minutes maximum age of cached position
} ) ;
expect ( successWatch ) . toBeDefined ( ) ;
} ) ;
} ) ;
} ) ;
} ;
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
exports . defineManualTests = function ( contentEl , createActionButton ) {
var watchLocationId = null ;
2016-04-12 17:33:37 -06:00
/ * *
* Set location status
* /
function setLocationStatus ( status ) {
document . getElementById ( 'location_status' ) . innerHTML = status ;
}
function setLocationDetails ( p ) {
var date = ( new Date ( p . timestamp ) ) ;
document . getElementById ( 'latitude' ) . innerHTML = p . coords . latitude ;
document . getElementById ( 'longitude' ) . innerHTML = p . coords . longitude ;
document . getElementById ( 'altitude' ) . innerHTML = p . coords . altitude ;
document . getElementById ( 'accuracy' ) . innerHTML = p . coords . accuracy ;
document . getElementById ( 'heading' ) . innerHTML = p . coords . heading ;
document . getElementById ( 'speed' ) . innerHTML = p . coords . speed ;
document . getElementById ( 'altitude_accuracy' ) . innerHTML = p . coords . altitudeAccuracy ;
document . getElementById ( 'timestamp' ) . innerHTML = date . toDateString ( ) + " " + date . toTimeString ( ) ;
}
/ * *
* Stop watching the location
* /
function stopLocation ( ) {
var geo = navigator . geolocation ;
if ( ! geo ) {
alert ( 'navigator.geolocation object is missing.' ) ;
return ;
}
setLocationStatus ( "Stopped" ) ;
if ( watchLocationId ) {
geo . clearWatch ( watchLocationId ) ;
watchLocationId = null ;
}
}
2016-03-15 18:21:34 -06:00
/ * *
* Start watching location
* /
var watchLocation = function ( ) {
var geo = navigator . geolocation ;
if ( ! geo ) {
alert ( 'navigator.geolocation object is missing.' ) ;
return ;
}
// Success callback
var success = function ( p ) {
setLocationDetails ( p ) ;
} ;
// Fail callback
var fail = function ( e ) {
console . log ( "watchLocation fail callback with error code " + e ) ;
stopLocation ( geo ) ;
} ;
// Get location
watchLocationId = geo . watchPosition ( success , fail , { enableHighAccuracy : true } ) ;
setLocationStatus ( "Running" ) ;
} ;
/ * *
* Get current location
* /
var getLocation = function ( opts ) {
var geo = navigator . geolocation ;
if ( ! geo ) {
alert ( 'navigator.geolocation object is missing.' ) ;
return ;
}
// Stop location if running
stopLocation ( geo ) ;
// Success callback
var success = function ( p ) {
setLocationDetails ( p ) ;
setLocationStatus ( "Done" ) ;
} ;
// Fail callback
var fail = function ( e ) {
console . log ( "getLocation fail callback with error code " + e . code ) ;
setLocationStatus ( "Error: " + e . code ) ;
} ;
setLocationStatus ( "Retrieving location..." ) ;
// Get location
geo . getCurrentPosition ( success , fail , opts || { enableHighAccuracy : true } ) ; //, {timeout: 10000});
} ;
/******************************************************************************/
var location _div = '<div id="info">' +
'<b>Status:</b> <span id="location_status">Stopped</span>' +
'<table width="100%">' ,
latitude = '<tr>' +
'<td><b>Latitude:</b></td>' +
'<td id="latitude"> </td>' +
'<td>(decimal degrees) geographic coordinate [<a href="http://dev.w3.org/geo/api/spec-source.html#lat">#ref]</a></td>' +
'</tr>' ,
longitude = '<tr>' +
'<td><b>Longitude:</b></td>' +
'<td id="longitude"> </td>' +
'<td>(decimal degrees) geographic coordinate [<a href="http://dev.w3.org/geo/api/spec-source.html#lat">#ref]</a></td>' +
'</tr>' ,
altitude = '<tr>' +
'<td><b>Altitude:</b></td>' +
'<td id="altitude"> </td>' +
'<td>null if not supported;<br>' +
'(meters) height above the [<a href="http://dev.w3.org/geo/api/spec-source.html#ref-wgs">WGS84</a>] ellipsoid. [<a href="http://dev.w3.org/geo/api/spec-source.html#altitude">#ref]</a></td>' +
'</tr>' ,
accuracy = '<tr>' +
'<td><b>Accuracy:</b></td>' +
'<td id="accuracy"> </td>' +
'<td>(meters; non-negative; 95% confidence level) the accuracy level of the latitude and longitude coordinates. [<a href="http://dev.w3.org/geo/api/spec-source.html#accuracy">#ref]</a></td>' +
'</tr>' ,
heading = '<tr>' +
'<td><b>Heading:</b></td>' +
'<td id="heading"> </td>' +
'<td>null if not supported;<br>' +
'NaN if speed == 0;<br>' +
'(degrees; 0° ≤ heading < 360°) direction of travel of the hosting device- counting clockwise relative to the true north. [<a href="http://dev.w3.org/geo/api/spec-source.html#heading">#ref]</a></td>' +
'</tr>' ,
speed = '<tr>' +
'<td><b>Speed:</b></td>' +
'<td id="speed"> </td>' +
'<td>null if not supported;<br>' +
'(meters per second; non-negative) magnitude of the horizontal component of the hosting device current velocity. [<a href="http://dev.w3.org/geo/api/spec-source.html#speed">#ref]</a></td>' +
'</tr>' ,
altitude _accuracy = '<tr>' +
'<td><b>Altitude Accuracy:</b></td>' +
'<td id="altitude_accuracy"> </td>' +
'<td>null if not supported;<br>(meters; non-negative; 95% confidence level) the accuracy level of the altitude. [<a href="http://dev.w3.org/geo/api/spec-source.html#altitude-accuracy">#ref]</a></td>' +
'</tr>' ,
time = '<tr>' +
'<td><b>Time:</b></td>' +
'<td id="timestamp"> </td>' +
'<td>(DOMTimeStamp) when the position was acquired [<a href="http://dev.w3.org/geo/api/spec-source.html#timestamp">#ref]</a></td>' +
'</tr>' +
'</table>' +
'</div>' ,
actions =
'<div id="cordova-getLocation"></div>' +
'Expected result: Will update all applicable values in status box for current location. Status will read Retrieving Location (may not see this if location is retrieved immediately) then Done.' +
'<p/> <div id="cordova-watchLocation"></div>' +
'Expected result: Will update all applicable values in status box for current location and update as location changes. Status will read Running.' +
'<p/> <div id="cordova-stopLocation"></div>' +
'Expected result: Will stop watching the location so values will not be updated. Status will read Stopped.' +
'<p/> <div id="cordova-getOld"></div>' +
'Expected result: Will update location values with a cached position that is up to 30 seconds old. Verify with time value. Status will read Done.' ,
values _info =
'<h3>Details about each value are listed below in the status box</h3>' ,
note =
'<h3>Allow use of current location, if prompted</h3>' ;
2016-04-12 17:33:37 -06:00
contentEl . innerHTML = values _info + location _div + latitude + longitude + altitude + accuracy + heading + speed +
altitude _accuracy + time + note + actions ;
2016-03-15 18:21:34 -06:00
createActionButton ( 'Get Location' , function ( ) {
getLocation ( ) ;
} , 'cordova-getLocation' ) ;
createActionButton ( 'Start Watching Location' , function ( ) {
watchLocation ( ) ;
} , 'cordova-watchLocation' ) ;
createActionButton ( 'Stop Watching Location' , function ( ) {
stopLocation ( ) ;
} , 'cordova-stopLocation' ) ;
createActionButton ( 'Get Location Up to 30 Sec Old' , function ( ) {
getLocation ( { maximumAge : 30000 } ) ;
} , 'cordova-getOld' ) ;
} ;