I am attempting to use Typeahead with my SignalR implementation.
What is happening is my Hub is getting hit and returning the value, but my result after .done() is undifined. I cannot work out why?
Javascript
$(function () {
var search = $.connection.searchHub;
$.connection.hub.start().done(function () {
$('#searchBar').typeahead(null, {
minLength: 2,
// begin source
source: function (query, process) {
var suggestions = [];// my callback value
search.server.search(query)
.done(function (result) {
console.log(result);
$.each(result, function () {
console.log(result);
suggestions.push(this);
process(suggestions);//process is a callback method
});
}).fail(function (error) {
console.log(error);
process([]);//process is a callback method, don't know if this is necessary here, but will produce no suggestions
});
}
});
});
Hub:
[HubName("searchHub")]
public class SearchHub : Hub
{
public async Task Search(string query)
{
api = new MovieApi();
var result = await api.Search(query);
if (result.results != null)
{
Clients.Client(Context.ConnectionId).results(result.results[0].title);
}
else
{
Clients.Client(Context.ConnectionId).noResults("There are no search results!");
}
}
}
Your search method does not return anything so its not strange that its undefined. You need to change to Task<T> and return something
Also I can not see that you are subscribing to results or noResults? Like
search.client.results = function(result) {
console.log(result);
};
edit: Also its very strange to use SIgnalR for this, standard REST with request/response should be fine here
Related
When i created this question, my doubt was about how would i be able to test an asynchronous request utilizing mocha/enzyme/chai/sinon.
I am sure that there are different ways, but a possible one is to mock it with a handmade function that returns the appropriate values (check the answer for details).
My getInitialState method is this:
getInitialState: function() {
var me = this;
var documentData = null;
var promise = me.getDocuments();
promise.then(function(value) {
var documents = value.map(function(obj) {
return Object.keys(obj).sort().map(function(key) {
return obj[key];
});
});
documentData = documents;
});
return ({
cd: false
});
},
And the getDocuments() function that returns a promise is this:
getDocuments: function() {
var deferred = when.defer();
Collection.fetch({cd: workspaceInfo.getCD()}).then(
function(results) {
deferred.resolve(results);
},
deferred.reject
);
return deferred.promise;
},
How can i successfuly test it?
Would i have to mock the getInitialState method itself? (is that even possible)
Or just the getDocuments function with some predictable return values?
Thanks in advance, any help will be appreciated.
I solved this by requiring the Collection (which is a rest API that brings some values from a database)
var Collection = require("path/to/my/collection/Collection");
Afterwards, i use it in my getDefaultProps() method:
getDefaultProps() {
return {
Collection: new Collection()
};
},
And this in turn enables me to write tests that initialize a mocked Collection (fileDataResponse is a JSON with some data):
var CollectionMock= {
fetch: () => {
return {
then: callback => callback(fileDataResponse)
};
}
};
And use it in my test afterwards:
it("should open the modal without a loaded configuration", function() {
var instance, wrapper;
wrapper = mount(
<DocumentPreview
Collection={CollectionMock}/>
);
instance = wrapper.component.getInstance();
instance.openModal();
expect(wrapper.find('#MockedTest' + 'docOid251085').exists()).to.equal(true);
wrapper.unmount();
});
I need some help.
This is fragment of my code, i can't return boolean from it("present or not")
, so everything is working incorrectly. where I was mistaken?
describe("first TEST", function () {
var boolean, parsingAllProfiles, getRandomProfile, randomProfile;
it("present or not", function () {
freelan.notFreelancersFound.isPresent().then(function (result) {
**return boolean = result;**
})
})
if (boolean) {
console.log("NOTHING!!!!!")
} else {
it("array of profiles", function() {
Promise.resolve(freelan.parsingAllProfilePage()).then(function (profiles) {
var arrForCheck = freelan.cloneArray(profiles);
freelan.checkKeywordInProfile(arrForCheck, params.keyword);
return randomProfile = profiles[Math.floor(Math.random() * profiles.length)];
})
});
}
});
I'm not sure exactly what you are trying to do with the boolean, but here's what it might look like in a test with chained promises.
describe("first TEST", function () {
var boolean, parsingAllProfiles, getRandomProfile, randomProfile;
it("present or not", function () {
freelan.notFreelancersFound.isPresent().then(function(result) {
if (result) {
freelan.parsingAllProfilePage().then(function(profiles) {
var arrForCheck = freelan.cloneArray(profiles);
expect(freelan.checkKeywordInProfile(arrForCheck, params.keyword).toBe(true);
});
} else {
console.log("NOTHING!!!!!");
}
});
});
});
I don't know the library in question, but promise-based code async, meaning that this inner code **return boolean = result;** won't run until after other things in the main function.
it("present or not", function () {
freelan.notFreelancersFound.isPresent().then(function (result) {
**return boolean = result;**
})
})
What you really need to do is read up on Promises and learn how to chain then. If you return a promise from your test, it will wait for that promise to resolve before moving onto the next test.
I have API service:
var SearchSuggestionApi = function (Restangular) {
return {
getSuggestion: function (keyword) {
return Restangular.one('search').customGET(null, {keyword:keyword});
}
};
};
SearchSuggestionApi.$inject = [
'Restangular'
];
I have controller to call this API:
vm.getSuggestion = function (keyword) {
SearchSuggestionApi.getSuggestion(keyword)
.then(
function (data) {
vm.listData = data;
}, function (error) {
console.log(error);
});
};
My problem is when I call vm.getSuggestion(keyword) two or many time (must call than one time). Such as:
vm.getSuggestion('a'); // => Return a array with many object in this
vm.getSuggestion('a b');// => Return empty array
Because vm.getSuggestion('a') return many data, it will finish after vm.getSuggestion('a b'). So vm.listData is [{object1}, {object2}, ...], but I want to vm.listData is [] (response data of the last function).
How can to cancel pending API call in first function when I call seconds function or another ways to get the last response data and set for vm.listData.
I researched some articles about cancel pending API calls, but it not help me about my problem.
Thanks for your help :)
There are various ways of solving this:
You can simply check in your then callback whether the value received is still current:
vm.getSuggestion = function (keyword) {
SearchSuggestionApi.getSuggestion(keyword)
.then(
function (data) {
if (vm.keyword === keyword) {
vm.listData = data;
}
}, function (error) {
console.log(error);
});
};
You can cancel the request by specifying a timeout promise
If you are solving this problem often, you might wish to replace the promise by an RxJS observable stream with the appropriate operators. This is the cleanest solution, but does require an additional library.
I have moved some common code to factory. but the controller is executing before factory get loaded. In this case i am getting the blank response(zero results)
can anyone suggest the best solution.
here is my angular factory,
app.factory('TabsFactory', function($resource){
var activetabs = {};
activetabs.getDepositAccountDetails = function() {
return $resource('xxxx/:number', {}, {
getDepositAccountDetailsService: {
method: 'GET',
isArray: false
}
});
}
activetabs.getAccountInfo = function(){
return accountinit.accountInfo;
}
activetabs.setAccountInfo = function(accountnumber, result) {
var accountinit = {
accountInfo: []
}
if (result.code == "v") {
activetabs.getDepositAccountDetails().getDepositAccountDetailsService({
number: accountnumber
}).$promise.then(function(response) {
accountinit.accountInfo = response;
//here i am getting the JSON response
}, function(error) {
});
}
return accountinit;
}
return activetabs;
});
controller,
TabsFactory.setAccountInfo(accountnumber, $scope.accountInfo);
$scope.accountInfo = TabsFactory.getAccountInfo();
alert(JSON.stringify($scope.accountInfo));
You should use chain promise to update scope variable, because your accountInfo variable is updated inside $resource promise.
Code
TabsFactory.setAccountInfo(accountnumber, $scope.accountInfo).then(function(data){
$scope.accountInfo = TabsFactory.getAccountInfo();
alert(JSON.stringify($scope.accountInfo));
});
Update
Service method should return promise inorder to continue promise chain
activetabs.setAccountInfo = function(accountnumber, result) {
var accountinit = {
accountInfo: []
}
if (result.code == "v") {
//added return below
return activetabs.getDepositAccountDetails().getDepositAccountDetailsService({
number: accountnumber
}).$promise.then(function(response) {
accountinit.accountInfo = response;
return accountinit.accountInfo;
//here i am getting the JSON response
}, function(error) {
});
}
return accountinit;
}
Yes, this will happen because of JavaScript executing asynchronous operations but your controller in such a way that it expects things to be synchronous operations.
When you call TabsFactory.getAccountInfo() its possible that your $resource('xxxx/:number') is still not completed and response ready for you to process!!
So, what to do? You have make use of promise. I usually have a repository (A factory with method that return promise) to handle server communications. Here is an example:
app.factory('accountRepository', ["$http","$q",function($http,$q){
return {
getDepositAccountDetails : function(id) {
var deferred = $q.defer();
$http.ger('xxx').success(deferred.resolve).error(deferred.reject);
return deferred.promise;
}
};
}] );
My repository will have more operations like add account, update account info etc..
my controller/service then calls these methods as follows:
accountRepository.getDepositAccountDetails(123).then(function(response) {
// Process the response..
}, function(error) {
// Some error occured! handle it
});
doing so, my code gets executed only after I get response from server and data is ready for consumption or display. Hope this helps..
Update: You might want to have a look at this to get the idea ;)
I'm writing a javascript test for my UserRepository.
I want to stub the data in the success callback function of the $http object.
User Repository code:
function UserRepository($http) {
return {
getUsers: function () {
$http({ url: '/GetUsers' }).success(function (data) {
//populate users
});
return users;
}
};
}
My test code:
var httpStub = function() {
return new {
success: function(callback) {
var array = [];
array.push({ forename: 'john', surname: 'smith' });
callback(array);
}
};
};
var userRepository = new UserRepository(httpStub);
userRepository.getUsers();
The error i'm getting is "the object is not function" which i think is happening where my httpstub returns the object literal containing the success function, but I can't figure out how to fix it.
I've fixed the problem. The httpStub was doing
return new{
success : function .....
}
When there should have been no new keyword e.g:
return {
success : function .....
}