I am trying to run some facebook query just after initializing the api using the following code :
window.fbAsyncInit = function() {
FB.init({...});
makeCall(); // this won't work
setTimeout(makeCall, 1000); // this will work
};
var makeCall = function() {
console.log("exec some query ")
var query = FB.Data.query("SELECT ...");
query.wait(function(friends) {
console.log("query result ...");
});
}
Somehow the query only get executed when I set a time out. Is there some better way of doing that rather than setting some timeout
try to move makeCall definition inside the window.fbAsyncInit = function() scope
for example immediately after FB.init call.
hope this helps
Related
I am trying to execute executeAsyncScript using the following code:
function get(url) {
var callback = function(args) {
console.log(args);
};
var defer = protractor.promise.defer();
browser.executeAsyncScript(function (url, callback) {
console.log("url" + url);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
console.log(xhr.responseText);
callback(xhr.responseText);
defer.fulfill(xhr);
}
}
xhr.open('GET', url , true);
xhr.send();
}, url);
return defer.promise;
};
function setupCommon() {
return get('https://example.com/rest/api/getsomething');
}
var flow = protractor.promise.controlFlow();
flow.execute(setupCommon);
If I execute the code that is passed to executeAsyncScript directly in the browser console then it works. I get the expected output.
console.log("url" + url);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
console.log(xhr.responseText);
callback(xhr.responseText);
defer.fulfill(xhr);
}
}
xhr.open('GET', 'https://example.com/rest/api/getsomething', true);
xhr.send();
But when I execute it using executeAsyncScript, it times out saying:
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
The restapi shouldn't have taken much time. I am new to all this. I am not sure what I am doing wrong. Can someone please help me with this.
The default timeout for Jasmine is 2000 milli-seconds which looks inadequate in your case as it looks like you indeed have lot of steps
Check the config file reference doc here for different timeout configurations from the protractor.conf.js
You can either increase the timeout at config level as in below
defaultTimeoutInterval: 60000,
allScriptsTimeout:90000
Or increase it for this test case alone
this.timeout(60000)
The default timeout for a script to be executed is 0ms. In most cases, including the examples below, one must set the script timeout WebDriver.Timeouts.setScriptTimeout(long, java.util.concurrent.TimeUnit) beforehand to a value sufficiently large enough.
Here is link for Java API that provides above information
https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/JavascriptExecutor.html#executeAsyncScript-java.lang.String-java.lang.Object...-
There's a troncated code of a page Object in protractor
that code is working :
var HomePage = function() {
this.publishedShows = element.all(by.repeater('show in showsHomePage'));
this.getFirstShow = function(){
return this.publishedShows.first();
}
};
this one is not :
var HomePage = function() {
this.publishedShows = element.all(by.repeater('show in showsHomePage'));
this.getFirstShow = function(){
return this.publishedShows.get(0);
}
};
I get this error :
Index out of bound. Trying to access element at index: 0, but there are only 0 elements that match locator by.repeater("show in showsHomePage")
Anyone can inlight me?
It is not about get(0) vs first() - they are absolutely the same in terms of implementation. It is probably about the timing, wait for the presence of the element before making any action with it:
var elm = myPageObject.getFirstShow();
var EC = protractor.ExpectedConditions;
browser.wait(EC.presenceOf(elm), 5000);
// do smth with elm
alecxe does have a point about waiting for the element to be present and so you may want to the wait as mentioned or browser.waitForAngular();
What I have seen is that if you resolve a finder to a variable then this can get left in the unfulfilled promise state (even though the internals have resolved the query). What needs to be done is to resolve the promise and then you should be able to get the element you require:
So from your code:
`this.publishedShows = element.all(by.repeater('show in showsHomePage'));`
Will still be a promise and not publishedShows.
This returns items when I try your code (I have a slightly different repeater).
var HomePage = function() {
this.publishedShows = element.all(by.repeater('show in showsHomePage'));
this.getFirstShow = function() {
return this.publishedShows.then(function(items){
=>return items[0].getText();
});
}
};
var hp = new HomePage();
=>expect(hp.getFirstShow()).toEqual('hello');
Obviously change your expect to what you want to check for and also the return too. Marked with =>
Ensure also that if you use any track by statement then you should look at the by.exactRepeater command to have an exact match on only the repeater part.
This worked for me, note the resolved promise returns an array of finders.
When user refresh a certain page, I want to set some initial values from the mongoDB database.
I tried using the onRendered method, which in the documentation states will run when the template that it is run on is inserted into the DOM. However, the database is not available at that instance?
When I try to access the database from the function:
Template.scienceMC.onRendered(function() {
var currentRad = radiationCollection.find().fetch()[0].rad;
}
I get the following error messages:
Exception from Tracker afterFlush function:
TypeError: Cannot read property 'rad' of undefined
However, when I run the line radiationCollection.find().fetch()[0].rad; in the console I can access the value?
How can I make sure that the copy of the mongoDB is available?
The best way for me was to use the waitOn function in the router. Thanks to #David Weldon for the tip.
Router.route('/templateName', {
waitOn: function () {
return Meteor.subscribe('collectionName');
},
action: function () {
// render all templates and regions for this route
this.render();
}
});
You need to setup a proper publication (it seems you did) and subscribe in the route parameters. If you want to make sure that you effectively have your data in the onRendered function, you need to add an extra step.
Here is an example of how to make it in your route definition:
this.templateController = RouteController.extend({
template: "YourTemplate",
action: function() {
if(this.isReady()) { this.render(); } else { this.render("yourTemplate"); this.render("loading");}
/*ACTION_FUNCTION*/
},
isReady: function() {
var subs = [
Meteor.subscribe("yoursubscription1"),
Meteor.subscribe("yoursubscription2")
];
var ready = true;
_.each(subs, function(sub) {
if(!sub.ready())
ready = false;
});
return ready;
},
data: function() {
return {
params: this.params || {}, //if you have params
yourData: radiationCollection.find()
};
}
});
In this example you get,in the onRendered function, your data both using this.data.yourData or radiationCollection.find()
EDIT: as #David Weldon stated in comment, you could also use an easier alternative: waitOn
I can't see your collection, so I can't guarantee that rad is a key in your collection, that said I believe your problem is that you collection isn't available yet. As #David Weldon says, you need to guard or wait on your subscription to be available (remember it has to load).
What I do in ironrouter is this:
data:function(){
var currentRad = radiationCollection.find().fetch()[0].rad;
if (typeof currentRad != 'undefined') {
// if typeof currentRad is not undefined
return currentRad;
}
}
I'm new to AngularJS and to JS testing in general and I'm having trouble wrapping my mind around how to go about testing this rather simple service. I've tried using $httpBackend with 'when' and 'expect' GET in variations configurations, to no avail. The test should verify that 1) data is returned via the deferred.resolve and 2) no data is returned via the deferred.reject. If someone could point me in the right direction i'd be quite grateful. Thanks!
btw: I'm using Jasmine + Testacular
.service('myService', function($http, $q) {
return {
getMyData: function() {
var deferred = $q.defer();
$http.get('/foo/bar.do').success(function(data) {
deferred.resolve(data);
}).error(function(){
deferred.reject();
});
return deferred.promise;
}
}
})
I had kind of the same problem testing a service with $http and $q.
Here is one of my test which passes:
it('should issue a GET request to /foo/bar.do', inject(function ($httpBackend) {
$httpBackend.when('GET', '/foo/bar.do').respond('success');
var finalResult = '';
var result = myService.getMyData();
result.then(function(data) {
finalResult = data;
}, function() {
console.log('error');
});
$httpBackend.flush();
expect(finalResult).toBe('success');
}));
I've tried to understand this post regarding this concept, however, I'm failing to get it. I have the following simple setup:
/server/test.js
Meteor.methods({
abc: function() {
var result = {};
result.foo = "Hello ";
result.bar = "World!";
return result;
}
});
/client/myapp.js
var q = Meteor.call('abc');
console.log(q);
This structure returns to the console undefined.
If I change the myapp.js file to:
Meteor.call('abc', function(err, data) {
!err ? console.log(data) : console.log(err);
}
I receive the Object in my console.
Ideally this is what I'd like to be able to do, but it doesn't work, stating in the console: Cannot read property 'greeting' of undefined
/client/myapp.js
var q = Meteor.call('abc');
Template.hello.greeting = function() {
return q.foo;
}
Any help in passing the data from the server object into the template would be greatly appreciated. I'm still learning JavaScript & Meteor.
Thanks!
From the Meteor.call documentation:
On the client, if you do not pass a callback and you are not inside a stub, call will return undefined, and you will have no way to get the return value of the method. That is because the client doesn't have fibers, so there is not actually any way it can block on the remote execution of a method.
So, you'll want to do it like this:
Meteor.call('abc', function(err, data) {
if (err)
console.log(err);
Session.set('q', data);
});
Template.hello.greeting = function() {
return Session.get('q').foo;
};
This will reactively update the template once the data is available.
This happens because Npm.require has Async behavior. That's the reason that you have to write a callback for Meteor.call.
But there is a solution, just use install(mrt add npm) and you'll get a function named Meteor.sync(//...) with this you can do both games: sync and async in your Meteor.call().
Reference: http://www.sitepoint.com/create-a-meteor-app-using-npm-module/
You can get the return value of a Meteor method for use in a template by using a reactive variable. Check out the working demonstration on Meteorpad
I went for a ghetto solution. But, it works for me, which is what matters, to me. Below is my code, which, in concept, I think, solves OP's problem.
In the client's main.js:
Meteor.setInterval(function() {
confirmLogin();
}, 5000);
This runs the confirmLogin() function every five seconds.
The confirmLogin function (in the client's main.js):
function confirmLogin() {
Meteor.call('loggedIn', function (error, result) {
Session.set("loggedIn", result);
});
}
The loggedIn method (in the server's main.js):
loggedIn: function () {
var toReturn = false;
var userDetails = Meteor.user();
if (typeof userDetails["services"] !== "undefined") {
if (typeof userDetails["services"]["facebook"] != "undefined") {
toReturn = true;
}
}
return toReturn;
},
The relevant helper:
loggedIn: function () {
return Session.get("loggedIn");
}