I have the code:
country: (origin) ->
#geocoder = new google.maps.Geocoder
#geocoder.geocode(
'latLng': origin,
(results, status) =>
if status is google.maps.GeocoderStatus.OK
return results[6]
else alert("Geocode was not successful for the following reason: " + status);
)
I am calling it in backbone.js as:
test = #country(origin)
console.log(test)
As a test I am using the console.log. However I am getting an:
undefined
response, as the country function is not returning anything. I know that results[6] has data in it, as I can do a conolse.log there and it returns.
How can I make the country function return result[6] when called?
I don't know that API, per se, but it looks like it's asynchronous, which means you cannot get the function to return the value. Instead, you'll have to pass in a continuation function that deals with the result when it becomes available.
country: (origin, handleResult) ->
#geocoder = new google.maps.Geocoder
#geocoder.geocode(
'latLng': origin,
(results, status) =>
if status is google.maps.GeocoderStatus.OK
handleResult(results[6])
else alert("Geocode was not successful for the following reason: " + status);
)
To use this, simply craft a function that knows what to do with the result and pass it to the country function:
obj.country origin, (result) ->
alert 'Got #{result} from Google'
In CoffeeScript the last expression in the function is returned, as in Ruby.
Here, your returning the result of your console.log
typeof console.log("123")
> "undefined"
I've noticed some people avoid this by putting a single # as the last line, which would just return this instead and avoids some awkward syntax.
Related
I am trying to call an API in second feature file , passing arguments from first feature file . These has to be passed as a param for second API
* def activeDetails =
"""
function(times){
for(i=0;i<=times;i++){
karate.log('Run test round: '+(i+1));
karate.call('getActiveRouteDetails.feature', { token: token, currentPage: i });
}
java.lang.Thread.sleep(1*1000);
}
"""
* call activeDetails totalPages
In my second feature , I am able to print the values passed , Getting error while passing it as a param 'no step-definition method match found for: param pageNumber'
And print currentPage
And print token
And param pageNumber = '#currentPage'
And param token = token
Watch the white space around the = sign. Normally if you use IDE support you can avoid these issues. You seem to have an extra space after pageNumber.
So make this change:
And param pageNumber = currentPage
I request you to please read the docs and examples. You are still un-necessarily making 2 calls. And over complicating your test.
I am trying to iterate through the array get the value and search the database, then concatenate the database result to the string translation
app.get('/translate',function(req,res) {
let translate = '';
['hello','love'].forEach(async (word) => {
let trans = await
NaijaLang.find({"engword": word, "naijalang": "yoruba"});
translate +=" " + trans[0].translation;
//Returns values
console.log(translate)
});
//Returns Empty String;
console.log(translate)
res.send(translate);
});
Because you do some async stuff there, but you send the value synchronously. Basically, this code will run in this order:
run let translate='';
run ['hello','love'].forEach(...)
run await NaijaLang.find(...) asynchronously for word=hello
run await NaijaLang.find(...) asynchronously for word=love
run console.log(translate) and res.send(translate);
resolve the value of await NaijaLang.find(...) -> this is the time when the translate is updated for the first time (either for word=hello or word=love. Whatever finishes earlier)
resolve the value of second call await NaijaLang.find(...) -> this is the time when the translate is updated for the second time. But the value was already send in the 5th step.
You can find more detailed explanation here: https://blog.lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795
And you can also find there how to fix it. You can use the for-of loop instead of forEach:
app.get('/translate',function(req,res){
let translate='';
for (let word of ['hello','love']) {
let trans=await NaijaLang.find({"engword":word,"naijalang":"yoruba"});
translate+=" " + trans[0].translation;
//Returns values
console.log(translate)
}
//Returns Empty String;
console.log(translate)
res.send(translate);
});
This time, the code will execute as you probably want. First, the find method will be called for word=hello, then, after the execution is finished, the find method will be called for word=love and finally after both calls are finished, the res.send will be called.
How to call parent function result in child function so that i can be able to alert() the result of parent function in child function
var query = "SELECT * FROM inventory WHERE status=1"; $cordovaSQLite.execute(db, query, []).then(function(success) {
for(var i=0;i<success.rows.length;i++){
var queryw = "SELECT * FROM purchase WHERE inventory_id="+success.rows.item(i).id+"";
$cordovaSQLite.execute(db, queryw, []).then(function(sccess) {
var kkk=0;
if(sccess.rows.item(0).remain==''){kkk=0;}else{kkk=sccess.rows.item(0).remain;}
alert(success.rows.item(i).id+'--'+success.rows.item(i).name+'--'+sccess.rows.item(0).remain);
$scope.isuccs.push({id:success.rows.item(i).id,name:success.rows.item(i).name,price:success.rows.item(i).price,qty:kkk});
},function (error) {alert("Error last inventory");
});
}
$scope.selectedItem=[];
$scope.selectedItem={price:''}; }, function (error) {
//console.error(err);
alert("Error retrieving inventory");
});
Your problem is simply that a promise's success (or failure) callback will not trigger until after all the remaining code has finished executing. In particular your for loop will have finished executing so by the time you use it i always has the value success.rows.length. You have to extract the body of the loop out into a separate function to create a separate closure that will not be affected by the for loop.
var query = "SELECT * FROM inventory WHERE status=1";
var queryw = "SELECT * FROM purchase WHERE inventory_id=?";
function get_inventory_item(row) {
$cordovaSQLite.execute(db, queryw, [row.id]).then(function(sccess) {
var kkk=0;
if(sccess.rows.item(0).remain==''){
kkk=0;
}else{
kkk=sccess.rows.item(0).remain;
}
alert(row.id+'--'+row.name+'--'+sccess.rows.item(0).remain);
$scope.isuccs.push({
id: row.id,
name: row.name,
price: row.price,
qty:kkk
});
});
}
$cordovaSQLite.execute(db, query, []).then(function(success) {
for(var i=0;i<success.rows.length;i++){
get_inventory_item(success.rows.item(i);
}
$scope.selectedItem=[];
$scope.selectedItem={price:''};
}, function (error) {
//console.error(err);
alert("Error retrieving inventory");
});
N.B. Also try to get into the habit of using parametrised sql queries rather than inserting parameters into the string itself.
I've resisted the temptation to restructure your code beyond laying it out legibly and doing the required extraction into a separate function, but I think you could probably end up with something much clearer if you made get_inventory_item return the promise and the success method in that function return the object it creates instead of pushing it into a scope object. The push is problematic because you don't know what order the values will be returned, if you returned the object then the main code body can use $q.all() to simply get an array of all the resulting values in the order returned by the original query.
Or, of course, an even simpler and faster solution would be to replace the pair of queries with a single query using join to get a complete row of all the fields together.
Problem
Calling repeater('#myTable tr','Rows').count(); returns a Future, not an integer. I need to get the integer value so I can confirm that an additional row was added to a table.
Code
it('should add a new user when save button is clicked',function()
{
showModal();
//here I'm trynig to store the row count of my table into a local variable.
//a future is returned who's 'value' field is undefined.
var memberCount = repeater('#memberTable tr','Member Rows').count();
//this outputs 'undefined'
console.log(memberCount.value);
input('editedMember.name').enter('John');
input('editedMember.grade').enter(5);
input('editedMember.ladderPosition').enter(3);
element('#saveMemberButton').click();
sleep(1);
expect(element(modalId).css('display')).toBe('none');
//here is where I want to do the comparison against the above stored memberCount
expect(repeater('#memberTable tr', 'Member Rows').count()).toBe(memberCount.value + 1);
});
Test Result
Chrome 25.0 e2e should add a new user when save button is clicked FAILED
expect repeater 'Member Rows ( #memberTable tr )' count toBe null
/Users/jgordon/learning/chessClub/web-app/test/e2e/scenarios.js:45:3: expected null but was 6
Chrome 25.0: Executed 2 of 2 (1 FAILED) (1 min 4.117 secs / 1 min 3.773 secs)
Drilling into the source code for Angularjs' e2e support reveals that you have to call execute() on the Future to have it populate its value. Also, when you call execute you have to provide a "done" function to the execute() otherwise Testacular will (oddly enough!) skip your test.
Code
var rowCountFuture = repeater('#memberTable tr','Member Rows').count();
rowCountFuture.execute(function(){
});
var memberCount = rowCountFuture.value;
While I'm jazzed to see this works, I'm concerned there may be some asynchronous bugs that could come out of this, also, I feel like this is a hack and not the right way to do it. Any ideas?
Based on the latest Protractor version:
it('should add a new user when save button is clicked', function() {
var memberCount;
element.all(by.repeater('#memberTable tr','Member Rows')).count().then(function(value) {
memberCount = value;
});
...
// then do all your entering user info, saving etc.
...
browser.refresh(); // or however you want to load new data
expect(element.all(by.repeater('#memberTable tr','Member Rows')).count()).toEqual(memberCount + 1);
});
I've run into the same issue, and have seen confusing results when testing value returned after calling execute(). I've found this method works more reliably:
var getCount = repeater('ul li').count();
getCount.execute(function(value) {
expect(value).toEqual(3);
});
You can do this most easily in the async promise returned by the locator
element.all(By.repeater 'thing in things').then(function(elements){
count = elements.length;
expect(count).toEqual(3);
});
I am trying to fetch a collection x times, incrementing a counter each time. The issue I am having is that since I need to render a view in the callback, and since .fetch() is asynchronous, I cannot simply perform a javascript loop. I would like to somehow tell it in the success callback to call itself again, without getting into an infinite loop.
Here's what I have:
#collection.fetch
data: {q: letters, i: i}
success:
#renderList()
How can I make this run x times, incrementing i each time, while waiting until #renderList is complete before running it again?
UPDATE
So, I'm making progress - this seems to be working, but it looks terrible:
#collection.fetch
data: {q: letters, i: 1}
success:
#collection.fetch
data: {q:letters, i:2}
success:
#collection.fetch
data: {q:letters, i:3}
Also, the success callback is giving me this warning in console:
Uncaught TypeError: object is not a function
Advice?
Maybe try recursive function like this (it's only example):
recursiveFetch = (collection, successCallback, counter, data) ->
if counter == 0
successCallback()
return
data.i = counter
collection.fetch
data: data
success: -> recursiveFetch(collection, successCallback, counter-1, data)
and call it like this:
recursiveFetch(#collection, => #renderList(), i, {q:letters})