Geolocation unit test with JsTestDriver - javascript

I'm testing geolocation using JsTestDriver, this is my code:
GeoLocationTest.prototype.testLocation = function(){
expectAsserts(1);
var coordinate = new Coordinate();
var location = coordinate.getLocation();
assertEquals("1,1",location);
};
Te test always fails because it tests immediately, before getting the geolocation coordinates. I tried using a timeout but the test also executes immediately.
setTimeout(function(){assertEquals("1,1",location);},10000);
And this is the javascript I'm trying to test
function Coordinate () {
this.latitude = 0.0;
this.longitude = 0.0;
this.date = new Date();
this.errorMsg = "";
}
Coordinate.prototype.getLocation = function(){
if (this.isBrowserSupported()){ //this test passes
navigator.geolocation.getCurrentPosition(this.setPosition,this.setError);
return "" + this.latitude + "," + this.longitude;
}
return "Browser not supported";
}
Coordinate.prototype.setPosition = function(position){
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
}
AssertError: expected "1,1" but was "0,0"

I was doing it wrong, hate JS
function Coordinate () {
latitude = 0.0;
longitude = 0.0;
date = new Date();
errorMsg = "";
}
Coordinate.prototype.getLocation = function(){
if (this.isBrowserSupported()){ //this test passes
navigator.geolocation.getCurrentPosition(this.setPosition,this.setError);
return 0;
}
return -1;
}
Coordinate.prototype.setPosition = function(position){
Coordinate.prototype.latitude = position.coords.latitude;
Coordinate.prototype.longitude = position.coords.longitude;
}
And then the test
GeoLocationTest.prototype.testLocation = function(){
var timeout = 10000;
expectAsserts(2);
var coordinate = new Coordinate();
coordinate.getLocation();
setTimeout(function(){
assertEquals(1,Coordinate.prototype.latitude);
assertEquals(1,Coordinate.prototype.longitude);
console.log("testLocation finished");
},timeout);
};
JsTestDriver will output "AssertError: Expected '2' asserts but '0' encountered."
So open the browser, open the console and wait for the test to execute. I added the last log because if the test passes nothing happens, if it fails it outputs the failure.

Related

Google Sheets Script "Exceeded maximum execution time"

I'm having issues trying to deal with the "Exceeded maximum execution time" error I get when running my script in Google sheets. I've found a few solutions on here that I couldn't get working with my script. Any help would be greatly appreciated, here is the script I am trying to modify:
function getGeocodingRegion() {
return PropertiesService.getDocumentProperties().getProperty('GEOCODING_REGION') || 'au';
}
function addressToPosition() {
// Select a cell with an address and two blank spaces after it
var sheet = SpreadsheetApp.getActiveSheet();
var cells = sheet.getActiveRange();
var addressColumn = 1;
var addressRow;
var latColumn = addressColumn + 1;
var lngColumn = addressColumn + 2;
var API_KEY = "xxx";
var options = {
muteHttpExceptions: true,
contentType: "application/json",
};
for (addressRow = 1; addressRow <= cells.getNumRows(); ++addressRow) {
var address = cells.getCell(addressRow, addressColumn).getValue();
var serviceUrl = "https://maps.googleapis.com/maps/api/geocode/json?address=" + address + "&key=" + API_KEY;
// Logger.log(address);
// Logger.log(serviceUrl);
var response = UrlFetchApp.fetch(serviceUrl, options);
if (response.getResponseCode() == 200) {
var location = JSON.parse(response.getContentText());
// Logger.log(response.getContentText());
if (location["status"] == "OK") {
//return coordinates;
var lat = location["results"][0]["geometry"]["location"]["lat"];
var lng = location["results"][0]["geometry"]["location"]["lng"];
cells.getCell(addressRow, latColumn).setValue(lat);
cells.getCell(addressRow, lngColumn).setValue(lng);
}
}
}
};
function positionToAddress() {
var sheet = SpreadsheetApp.getActiveSheet();
var cells = sheet.getActiveRange();
// Must have selected 3 columns (Address, Lat, Lng).
// Must have selected at least 1 row.
if (cells.getNumColumns() != 3) {
Logger.log("Must select at least 3 columns: Address, Lat, Lng columns.");
return;
}
var addressColumn = 1;
var addressRow;
var latColumn = addressColumn + 1;
var lngColumn = addressColumn + 2;
//Maps.setAuthentication("acqa-test1", "AIzaSyBzNCaW2AQCCfpfJzkYZiQR8NHbHnRGDRg");
var geocoder = Maps.newGeocoder().setRegion(getGeocodingRegion());
var location;
for (addressRow = 1; addressRow <= cells.getNumRows(); ++addressRow) {
var lat = cells.getCell(addressRow, latColumn).getValue();
var lng = cells.getCell(addressRow, lngColumn).getValue();
// Geocode the lat, lng pair to an address.
location = geocoder.reverseGeocode(lat, lng);
// Only change cells if geocoder seems to have gotten a
// valid response.
Logger.log(location.status);
if (location.status == 'OK') {
var address = location["results"][0]["formatted_address"];
cells.getCell(addressRow, addressColumn).setValue(address);
}
}
};
function generateMenu() {
var entries = [{
name: "Geocode Selected Cells (Address to Lat, Long)",
functionName: "addressToPosition"
}, {
name: "Geocode Selected Cells (Address from Lat, Long)",
functionName: "positionToAddress"
}];
return entries;
}
function updateMenu() {
SpreadsheetApp.getActiveSpreadsheet().updateMenu('Geocode', generateMenu())
};
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
*
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
SpreadsheetApp.getActiveSpreadsheet().addMenu('Geocode', generateMenu());
};
Or, any other script you may know of that does geocode in Google sheets and already properly handles max execution time that would be OK too, I'm not tied to this specific script, just getting the outcome I need!
This error's cause is due to script running more than 6 minutes.
A possible solution is to limit the time-consuming part of your script (which is the for loop) to only 5 minutes. Then create a trigger and continue the loop into another instance if it still isn't done.
Script:
function addressToPosition() {
// Select a cell with an address and two blank spaces after it
var sheet = SpreadsheetApp.getActiveSheet();
...
var options = {
muteHttpExceptions: true,
contentType: "application/json",
};
// if lastRow is set, get value, else 0
var continueRow = ScriptProperties.getProperty("lastRow") || 0;
var startTime = Date.now();
var resume = true;
for (addressRow = ++continueRow; addressRow <= cells.getNumRows(); ++addressRow) {
var address = cells.getCell(addressRow, addressColumn).getValue();
...
// if 5 minutes is done
if ((Date.now() - startTime) >= 300000) {
// save what's the last row you processed then exit loop
ScriptProperties.setProperty("lastRow", addressRow)
break;
}
// if you reached last row, assign flag as false to prevent triggering the next run
else if (addressRow == cells.getNumRows())
resume = false;
}
// if addressRow is less than getNumRows()
if (resume) {
// after execution of loop, prepare the trigger for the same function
var next = ScriptApp.newTrigger("addressToPosition").timeBased();
// run script after 1 second to continue where you left off (on another instance)
next.after(1000).create();
}
}
Do the same thing with your other functions.

ReferenceError: API is not defined (Javascript)

I'm trying to make an App for meteo, but my api doesn't load.
When i call API in fetch it output: ReferenceError: API is not defined
It is my first app (also my first question on StackOverflow), this is the snippet:
window.addEventListener('load', () =>{
let long;
let lang;
let temperatureDescription = document.querySelector('.temperature-description');
let temperatureDegree = document.querySelector('.temperature-degree');
let locationTimezone = document.querySelector('.location-timezone');
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position=>{
long = position.coords.longitude;
lat = position.coords.latitude;
const proxy = 'https://cors-anyware.herouapp.com/';
const API = '${proxy}https://api.openweathermap.org/data/2.5/forecast?id=524901&APPID=cc6a4a00070dfbee1327390b072f88d6/${lat},${long}';
});
fetch(API).then(response=>{
return response.json();
}).then(data=>{
console.log(data);
const {
temperature,
summary
}
= data.currently;
//set DOM elements from the API
temperatureDegree.textContent = temperature;
});
};
}
);
Can anyone help me?
Thanks :)
Your API constant variable is block scoped, it means that it is accessible only inside of callback of getCurrentPosition function.
And also,navigator.geolocation.getCurrentPosition is asynchronous, you should call fetch inside the callback. otherwise fetch will execute before location lat lon is detected by browser.
window.addEventListener('load', () =>{
let long;
let lang;
let temperatureDescription = document.querySelector('.temperature-description');
let temperatureDegree = document.querySelector('.temperature-degree');
let locationTimezone = document.querySelector('.location-timezone');
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position=>{
long = position.coords.longitude;
lat = position.coords.latitude;
const proxy = 'https://cors-anyware.herouapp.com/';
const API = '${proxy}https://api.openweathermap.org/data/2.5/forecast?id=524901&APPID=cc6a4a00070dfbee1327390b072f88d6/${lat},${long}';
fetch(API).then(response=>{
return response.json();
}).then(data=>{
console.log(data);
const {
temperature,
summary
}
= data.currently;
//set DOM elements from the API
temperatureDegree.textContent = temperature;
});
});
};
}
);

i am getting undefined value in my javascript object property

i have a codepen that basically takes value from openweather and tries to set it according to an app state. I cannot seem to figure out why i am getting an undefined value for this.tempValue and this.tempType. here's the code:
`
var app = {
latitude: '',
longitude: '',
tempType : " C",
tempValue: "",
getGeoLoc: function (id) {
//Removed timeout option due to error
var options = {}; //{ timeout: 3 };
navigator.geolocation.getCurrentPosition(this.foundLoc.bind(this), this.noloc, options);
},
foundLoc : function(position) {
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
console.log('coords ', this.latitude, this.longitude);
// Call your get weather function
// Using call to bind the context of `this`
this.getWather.call(this);
},
// Error method
noloc: function(err) {
console.log(err.message);
},
// Method to get your weather after location is found
getWather: function() {
var url = 'http://api.openweathermap.org/data/2.5/weather?lat=' + this.latitude + '&lon=' + this.longitude +'&APPID=7bda183adf213c8cfa2ef68635588ef3';
console.log('URL is: '+url);
$.getJSON(url, function(data) {
console.log('Your weather data', data);
// Do your dom stuff here
$("#location").text(data.name);
console.log("#5 does this work??? ", data.main.temp.toString().slice(0, 2));
var temp = '';
this.tempValue = data.main.temp.toString().slice(0, 2);
var type = "";
type = this.tempType;
console.log("#6 what's inside tempType. ", this.tempType);
$("#temp").html(this.tempValue + this.tempType);
$("#message").html(data.weather[0].description);
console.log("#3 what is in the description property. ", data.weather[0].description);
//function to convert C to F and vice versa and return a string
function convert (value) {
var celsius = '';
var fahrenheit = '';
var convertedToF = 0;
var convertedToC = 0;
if(value == 'fahrenheit') {
convertedToF = data.main.temp * 9/5 + 32;
this.tempValue = convertedToF;
console.log("#4 fahrenheit value is ", convertedToF);
}
if(value == 'celsius') {
convertedToC = data.main.temp - 32;
convertedToC *= 5/9;
this.tempValue = convertedToC;
}
}
$("#convert").click( function () {
convert('celsius');
}
);
});
},
};
// Make sure to call your initialising function
app.getGeoLoc();
codepen url is: http://codepen.io/rush86999/pen/MKMywE/?editors=1010
Inside the success callBack of getJSON, the this object will point to jqXHR object(as mentioned by #dfsq). That is why you are seeing undefined for that two variables. There a different methods available to fix this. one of them would be,
$.getJSON(url, function(data) {
// ...YOUR CODE...
}.bind(this));

Uncaught TypeError: pos.apply is not a function in showtooltip() method

jQuery(document).ready(function($) {
var currentMap;var lat;var log;var latlongarray;var latitude;
var longitude;var count = 0;var name;var number;var country;
var maps;var address;var marker;var batch = [];
showTooltip = function(marker) {
tooltip.innerHTML = marker.tooltip;
var point = currentMap.getCurrentMapType().getProjection()
.fromLatLngToPixel(currentMap.fromDivPixelToLatLng(
new GPoint(0, 0),true),currentMap.getZoom());
var offset = currentMap.getCurrentMapType().getProjection()
.fromLatLngToPixel(marker.getPoint(),
currentMap.getZoom());
var anchor = marker.getIcon().iconAnchor;
var width = marker.getIcon().iconSize.width;
var height = tooltip.clientHeight;
var pos = new GControlPosition(G_ANCHOR_TOP_LEFT,
new GSize(offset.x - point.x - anchor.x + width,
offset.y - point.y - anchor.y - width));
pos.apply(tooltip);
tooltip.style.visibility = "visible";
}
initialize = function() {var tim = (new Date).getTime();
var provNum = $("input[name='providerNumber']").val();
$.getJSON('newmap.do?t=' + tim+ '&providerNumber='+ provNum,
function(data) {$.each(data,function(i,item) {
address = item.name + item.address;
name = item.name;
latitude = item.lattitude;
longitude = item.longitude;
number = item.number;
var icon = new GIcon();
icon.image = "images/pin.png";
icon.iconAnchor = new GPoint(16,16);
icon.infoWindowAnchor = new GPoint(16,0);
icon.iconSize = new GSize(32,32);
icon.shadowSize = new GSize(59,32);
marker = new GMarker(new GLatLng(item.lattitude,
item.longitude),{
draggable : true,
icon : icon
});
lat = item.lattitude;
log = item.longitude;
marker.disableDragging();
batch.push(marker);
marker.tooltip = "<div class='tooltip'>"+item.name+
'<br>'+ item.number+'<br>BEDS:'+ item.bed
+ '<br>DSH: '+ item.dsh+ "</div>";
GEvent.addListener(marker,"mouseover",function() {
showTooltip(marker);
});
GEvent.addListener(marker,"mouseout",function() {
tooltip.style.visibility = "hidden";
});
GEvent.addListener(marker,"mouseout",function() {
tooltip.style.visibility = "hidden";
});
});
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map-c"));
map.setCenter(new GLatLng(lat,log),11);
tooltip = document.createElement("div");
map.getPane(G_MAP_FLOAT_PANE).appendChild(tooltip);
tooltip.style.visibility = "hidden";
map.setUIToDefault();
mgr = new MarkerManager(map);
mgr.addMarkers(batch,2);
mgr.refresh();
currentMap = map;
}
});
});
}
if (jQuery.browser.safari&& document.readyState != "complete") {
initialize();
}
});
This is my code.. here iam getting lattitude and longitude from sql and adding marker in google map.Now iam trying to add infobox for each marker
but i got an error
" Uncaught TypeError: pos.apply is not a function "
at line
"pos.apply(tooltip);"
Do anyone know how to solve this?
.apply is part of Function.prototype, it is not available in normal object.
let me show you, what you are doing here.
var obj = {i : 10}
obj.apply(this); //Uncaught TypeError: obj.apply is not a function
You are Creating an object from new GControlPosition and on this object .apply is not available

Receiving WatchPosition only once

I use this code to get the first position ,and i want to keep getting it.
var init = function()
{
navigator.geolocation.getCurrentPosition(function(position)
{
new_position = position;
}, onError, {});
watchID = navigator.geolocation.watchPosition(UserLocationCalculation, onError, {maximumAge: 1000, timeout: 5000, enableHighAccuracy: true});
}
var UserLocationCalculation = function(position)
{
var d;
//alert("Position" + " Latitude " + position.coords.latitude + " Longitude " + position.coords.longitude);
if(new_position == 0)
{
new_position = position;
}
else
{
//Change the positions around
old_position = new_position;
new_position = position;
var conv_old_position = new google.maps.LatLng(old_position.coords.latitude, old_position.coords.longitude);
var conv_new_position = new google.maps.LatLng(new_position.coords.latitude, new_position.coords.longitude);
d = google.maps.geometry.spherical.computeDistanceBetween(conv_old_position, conv_new_position);
run_total = parseInt(run_total);
d = parseInt(d);
run_total += d;
navigator.geolocation.clearWatch( watchID );
}
}
Now i keep an old_position, a new_position and a run_total as global variables. I save the last position as the new, and the one before that as old, and then calculate the distance and add this to a global variable.
But the watchPosition calls the UserLocationCalculation only once, after that, it just doesn't call it anymore.
Your UserLocationCalculation function is only being called once because at the end of the else clause, you are calling navigator.geolocation.clearWatch( watchID );. Since you are calling this, the device stops watching for position changes, so it never fires again.
From the docs: Stop watching for changes to the device's location referenced by the watchID parameter.

Categories