Meteor.call() with Jasmine doesn't work properly - meteor

I have a problem with Meteor.methods. I need to test quite complicated function but i don't know how get the return value. For my own needs I wrote a trivial code:
Meteor.methods({
returnTrue: function() {
return true;
},
returnFalse: function(){
return false;
}
});
Then i wrote also trivial test in Jasmine:
describe("Function", function() {
var tmp;
it("expect to be true", function(){
Meteor.call('returnTrue', function(error, result){
if(error){
tmp = false;
}
else{
tmp = result;
}
});
expect(tmp).toBe(true);
});
});
And in my test i have Expected undefined to be true.
I was trying to go through it using Session.set and Session.get but with the same result.
Any idea how can i do that?

Here is a question that might peak your interest. A few things are misguided in your code:
Your call does not reach the actual server method
Your expect is called outside of the method's callback, hence tmp is not set yet!
Here is a suggestion!
describe("Function", function() {
var tmp;
it("expect to be true", function(){
spyOn(Meteor, "call").and.callThrough(); // to actually call the method
Meteor.call('returnTrue', function(error, result){
if(error){
tmp = false;
}
else{
tmp = result;
}
expect(tmp).toBe(true); // moved the check inside the callback, once the call is actually executed
});
expect(Meteor.call).toHaveBeenCalled(); // check if the method has been called
});
});

Related

Setting session variable inside callback function

I'm trying to set a session variable inside a callback function as such:
getPlayerName() {
Meteor.call("stocks.getPlayer", this.props.player.player, function(error, result){
if(error){
console.log(error.reason);
return;
}
Session.set('playerName', result.Name);
});
console.log(Session.get('playerName'));
}
But the console on the client side returns undefined. I've also tried using reactive variables:
getPlayerName() {
this.name = new ReactiveVar();
Meteor.call("stocks.getPlayer", this.props.player.player, function(error, result){
if(error){
console.log(error.reason);
return;
}
this.name.set(price);
}.bind(this));
console.log(this.name.get());
}
But this also returns undefined. How can I get this to work? Thank in advance.

Extracting data out of http call [duplicate]

I'm using Meteor for first time and i'm trying to have a simple http call within a method so i can call this method from the client.
The problem is that this async call it's keep running even if i put it within a wrapper.
Client side:
Meteor.call('getToken', function(error, results) {
console.log('entered');
if(error) {
console.log(error);
} else {
console.log(results);
}
});
Server Side
Meteor.methods({
getToken: function(){
// App url
var appUrl = 'myAppUrl';
// Key credentials
var apiKey = 'mykey';
var apiSecret = 'mySecret';
function asyncCall(){
Meteor.http.call(
'POST',
appUrl,
{
data: {
key: apiKey,
secret: apiSecret
}
}, function (err, res) {
if(err){
return err;
} else {
return res;
}
}
);
}
var syncCall = Meteor.wrapAsync(asyncCall);
// now you can return the result to client.
return syncCall;
}
});
I'm always getting an undefined return.
If i log the response within the http.post call i'm geting the correct response.
If i try to log the syncCall i get nothing.
I would very appreciate any help on this.
You should use the synchronous version of HTTP.post in this case. Give something like this a try:
Meteor.methods({
getToken: function() {
var appUrl = 'myAppUrl';
var data = {apiKey: 'mykey', apiSecret: 'mySecret'};
try {
var result = HTTP.post(appUrl, {data: data});
return result;
} catch (err) {
return err;
}
}
});
Instead of returning the err I'd recommend determining what kind of error was thrown and then just throw new Meteor.Error(...) so the client can see the error as its first callback argument.

Why asynchronous Meteor.call() doesn't return anything

I have the following code on the client-side:
Meteor.call("getOldTests", m_user, test_id, course, language, function (error, result) {
console.log("result: " + result);
if (error) {
Notifications.error(error.reason, 'We are working on this problem');
} else {
console.log(result);
data.set(course, result);
}
});
where the server-side has the following method:
Meteor.methods({
getOldTests: function (m_user, test_id, course, language) {
var tests = Tests.findOne({email: m_user.email, course_en: course, test_id: test_id});
if (tests) {
console.log(tests);
return Questions.find({course_en: course, variant: tests.variant, language: language});
} else {
return false;
}
},});
Where the variable data is reactive-dict
So, why is nothing executed inside of my Meteor.call() function on the client-side (no console output) while indeed it calls the method on the server-side (console outputs intermediate results)?
Thanks,
It looks like you are using a method where a pub-sub is more appropriate:
server:
Meteor.publish('getOldTests',function (m_user, test_id, course, language) {
var tests = Tests.findOne({email: m_user.email, course_en: course, test_id: test_id});
if (tests) return Questions.find({course_en: course, variant: tests.variant, language: language});
else this.ready();
});
client:
Meteor.subscribe('getOldTests',m_user, test_id, course, language);
Database fetch and API calls form server side should be contained inside a Fiber. Try this:
Future = Npm.require('fibers/future');
getOldTests: function (m_user, test_id, course, language) {
var myFuture = new Future();
var tests = Tests.findOne({email: m_user.email, course_en: course, test_id: test_id});
if (tests) {
console.log(tests);
myFuture.return(Questions.find({course_en: course, variant: tests.variant, language: language}));
} else {
return false;
}
return myFuture.wait();
}
This question might be helpful.

Meteor methods wait before execution on client proceeds

could anybody please tell me how to make clients wait until the called function on the server is executed?
My code:
Meteor.methods({
markLettersAsRead: function(userId) {
if(serverVar) {
Users.update({_id: userId}, {$set: {letters: []}}); // removing all references
}
}
});
Template.letter.events({
'click a': function() {
Meteor.call('markLettersAsRead', Meteor.userId(), this._id, function(err) {
if (err) {
console.log(err);
}
});
var usersExistsWithThisLetter = Users.find({letters: {_id: this._id}}).count();
console.log(usersExistsWithThisLetter);
}
});
In my example usersExistsWithThisLetter is always 1 because the Users.find() doesn't wait until the Meteor.call is done. I verified this by checking the database and no users exists with entries in the letters array.
Any help would be greatly appreciated.
You need to query the collection inside the callback, because then you can be certain that your server method has already been executed. I would do something like this (note the self variable declaration):
var self = this;
Meteor.call('markLettersAsRead', Meteor.userId(), this._id, function(err) {
if (!err) {
var usersExistsWithThisLetter = Users.find({letters: {_id: self._id}}).count();
console.log(usersExistsWithThisLetter);
} else {
console.log(err);
}
});
I hope it helps!

Can't get result data with $http angularjs

I'm trying to use $http, but why it return null result?
angular.module('myApp')
.factory('sender', function($http) {
var newData = null;
$http.get('test.html')
.success(function(data) {
newData = data;
console.log(newData)
})
.error(function() {
newData = 'error';
});
console.log(newData)
return newData
})
Console say: http://screencast.com/t/vBGkl2sThBd4. Why my newData first is null and then is defined? How to do it correctly?
As YardenST said, $http is asynchronous so you need to make sure that all functions or display logic that are dependent on the data that is returned by your $http.get(), gets handle accordingly. One way to accomplish this is to make use of the "promise" that $http returns:
Plunkr Demo
var myApp = angular.module('myApp', []);
myApp.factory('AvengersService', function ($http) {
var AvengersService = {
getCast: function () {
// $http returns a 'promise'
return $http.get("avengers.json").then(function (response) {
return response.data;
});
}
};
return AvengersService;
});
myApp.controller('AvengersCtrl', function($scope, $http, $log, AvengersService) {
// Assign service to scope if you'd like to be able call it from your view also
$scope.avengers = AvengersService;
// Call the async method and then do stuff with what is returned inside the function
AvengersService.getCast().then(function (asyncCastData) {
$scope.avengers.cast = asyncCastData;
});
// We can also use $watch to keep an eye out for when $scope.avengers.cast gets populated
$scope.$watch('avengers.cast', function (cast) {
// When $scope.avengers.cast has data, then run these functions
if (angular.isDefined(cast)) {
$log.info("$scope.avengers.cast has data");
}
});
});
This JavaScript code is asynchronous.
console.log(newData)
return newData
Is executed before what inside success
newData = data;
console.log(newData)
So at first time, the newData is null (you set it to be null)
And when the http response is returned (inside the success), the newData gets its new value.
This is very common in Javascript, you should do all your work inside the success.

Resources