WinJS Promise causes JavaScript exception in base.js - javascript

I am trying to implement a service inside of my WinJS Windows 8 App, the service needs to call winjs httpClient. I want my service to return a promise while it waits for the promise returned by httpClient . My service code is as follows
(function () {
"use strict";
var _httpClient = new Windows.Web.Http.HttpClient();
var _infoUri = new Windows.Foundation.Uri("https://news.google.com/");
var _getLatestInfo = function () {
return WinJS.Promise(function (completeCallback, errorCallback, progressCallback) {
// invoke the httpclient here
_httpClient.getAsync(_infoUri)
.then(function complete(result) {
completeCallback(result);
}, function error(result) {
errorCallback(result);
}, function progress(result) {
progressCallback(result);
});
});
};
WinJS.Namespace.define("DataService", {
getLatestInfo: _getLatestInfo
});
})();
And I call my service method as follows
(function () {
"use strict";
WinJS.UI.Pages.define("/pages/home/home.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
DataService.getLatestInfo().then(function () { }, function () { }, function () { });
}
});
})();
This does not work and I get an error like this
Exception was thrown at line 2018, column 13 in ms-appx://microsoft.winjs.2.0/js/base.js
0x800a01b6 - JavaScript runtime error: Object doesn't support property or method '_setState''
I tried simplifying my service as follows with no luck.
(function () {
"use strict";
var _getLatestInfo = function () {
return WinJS.Promise(function (a, b, c) { });
};
WinJS.Namespace.define("DataService", {
getLatestInfo: _getLatestInfo
});
})();
I don't know what the error is trying to tell me and how to correct this.

I just figured it out, I was missing the 'new' just before WinJS.Promise. Since WinJS.Promise is a class it apparently need to be newed. The error message only confused me more.

Related

Unable to capture unhandled errors on Ionic 1 apps

We are trying to setup a top level global unhadled error detector on our hybrid Ionic 1 app. Following this documentation, we have subscribed to window.addEventListener in order to do so, but it's capturing almost nothing. Then, we started using Angular's $exceptionHandler and it solves the issue partially, but it's still missing the HTTP and script errors. Details:
resource errors (image download errors, script parse errors) are not being handled by window.addEventListener nor by Angular's $exceptionHandler
errors thrown by controller loading, ionic events like beforeEnter, ionic methods called from the UI through template events bindings, ajax calls... none of them are handled by window.addEventListener - Angular's $exceptionHandler does handle them
Surprisingly, all code scheduled with a setTimeout from all those places is properly handled by window.addEventListener
Next files demonstrates all what has been assured:
// app.js
angular.module("starter", [dependencies]).config(function () {
window.addEventListener("error", function (event) {
console.error("Error caught", event);
});
});
.
// controllers.js
angular.module('starter.controllers', [dependencies]).controller("HomeCtrl", function ($scope, $http) {
var nullVariable = null;
var assignmentTarget;
$scope.testClick = function () {
setTimeout(function () {
assignmentTarget = nullVariable.testClickTimeout; // handled
}, 0);
assignmentTarget = nullVariable.testClick; // unhandled
};
$scope.$on('$ionicView.beforeEnter', function () {
setTimeout(function () {
assignmentTarget = nullVariable.homeCtrlBeforeEnterTimeout; // handled
}, 0);
assignmentTarget = nullVariable.homeCtrlBeforeEnter; // unhandled
});
$http({
method: "GET",
responseType: "json",
url: "comeurl"
}).then(function (response) {
setTimeout(function () {
assignmentTarget = nullVariable.ajaxResponseTimeout; // handled
}, 0);
assignmentTarget = nullVariable.ajaxResponse; // unhandled
});
setTimeout(function () {
assignmentTarget = nullVariable.homeCtrlTimeout; // handled
}, 0);
assignmentTarget = nullVariable.homeCtrl; // unhandled
});

Intern js :How to return PageObject of the page from the function which opens it ?

I'm working on a UI automation project using Intern js . And I'm implementing it using page object model . I have a simple scenario where user enters credentials in login page and is navigated to welcome page.
In my script i have a 'doLogin()' function in LoginPage which is responsible for entering credentials and clicking submit button.
Now the problem is i want doLogin() to return WelcomePage and i'm unable to figure out the way to do this.
Heres my code setUp:
LoginPage.js
define([],
function () {
function LoginPage(remote) {
this.remote = remote;
}
LoginPage.prototype = {
constructor: LoginPage,
// Login Page related Methods
doLogin: function(username,password){
this
.findById(json.locators.username).
.type(username).end()
.findById(json.locators.password)
.type(username).end()
.findByXpath(json.locators.sumit).click().end()
.sleep(1000).then(function(){
return welcomePage// this is not working
})
}
};
return LoginPage;
});
WelcomePage.js
define([],
function () {
function WelcomePage(remote) {
this.remote = remote;
}
WelcomePage.prototype = {
constructor: WelcomePage,
doSomething: function(){
//welcome page related method
}
};
return WelcomePage;
});
Now what i actually want to achive is to do something like:
loginpage.doLogin(usrname,password).doSomething();
can somebody help on this??
A more flexible way to implement page objects is to make them groups of helper functions (like Leadfoot's pollUntil) rather than Command-like objects.
Using that model, your LoginPage object might look like:
define([], function () {
return {
doLogin: function (username, password) {
return function () {
return this.parent
.findById(json.locators.username).
.type(username).end()
.findById(json.locators.password)
.type(username).end()
.findByXpath(json.locators.sumit).click().end()
.sleep(1000).then(function(){
return welcomePage// this is not working
});
}
}
};
});
WelcomePage might look like
define([], function () {
return {
doSomething: function () {
return function () {
return this.parent
// more stuff
}
}
};
});
You can call this.parent in the returned function because when the helper function is called (as a Command then callback) it's context will be set to the Command that's calling it.
You would use them like
define([
'./WelcomePage',
'./LoginPage',
// ...
], function (
welcomePage,
loginPage,
// ...
) {
// ...
this.remote
.get('some page')
.then(loginPage.doLogin('username', 'password'))
.then(welcomePage.doSomething())
// other stuff
// ...
});

SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started

Trying to replicate an example I have encountered the problem that the connection is not made, when it comes to do it from a server to my computer, but when I work remotely if it works.
Links example
link 1
link 2
This is my code
var app = angular.module('app', []);
app.value('$', $);
app.factory('signalRSvc', function ($, $rootScope) {
return {
proxy: null,
initialize: function (acceptGreetCallback) {
//Getting the connection object
connection = $.hubConnection('http://190.109.185.138:8016');
//Creating proxy
this.proxy = connection.createHubProxy('HelloWorldHub');
//Starting connection
connection.start({ jsonp: true }).done(function () {
alert("funciono");
});
connection.start({ jsonp: true }).fail(function () {
alert("fallo");
});
//connection.start({ jsonp: true }).done(function () {
// console.log("connection started!");
//});
//Attaching a callback to handle acceptGreet client call
this.proxy.on('acceptGreet', function (message) {
$rootScope.$apply(function () {
acceptGreetCallback(message);
});
});
},
sendRequest: function (callback) {
//Invoking greetAll method defined in hub
this.proxy.invoke('greetAll');
}
}
});
app.controller('SignalRAngularCtrl', function ($scope, signalRSvc) {
$scope.text = "";
$scope.greetAll = function () {
signalRSvc.sendRequest();
}
updateGreetingMessage = function (text) {
$scope.text = text;
}
signalRSvc.initialize(updateGreetingMessage);
});
You should only have one connection.start() and not two. You need to add the done() and fail() into that call.
connection.start({ ... }).done(function() {...}).fail(function() {...})
Otherwise you'll try to start it twice. It might seem to work locally since there is no delay but in actual conditions the first won't finish before the second.

Protractor : mocking EventSource

Is there remotely any way to mock any SSE (Server Sent Event) from a Protractor test ?
That means mocking EventSource
Angular controller :
angular.module('app').controller('HomeController', function() {
var monitoringEvents = new window.EventSource('/streams/jobserveur');
monitoringEvents.addEventListener('monitoring-event', function(e) {
var json = JSON.parse(e.data);
...
});
});
Thank you for any insight
I managed to mock EventSource by the solution I mentionned (angular module/protractor addMockModule).
Externalize EventSource calls into a dedicated angular module
angular.module('app.sse', [])
.value('$sse', {
sources : [],
addEventSource : function(name, url) {
this.sources[name] = new window.EventSource(url);
},
addEventListener : function(name, eventName, callback) {
this.sources[name].addEventListener(eventName, callback);
}
});
Referencing the module in the app
angular.module('app', ['app.sse', ...])
Use the $sse module in the app
angular.module('app').controller('HomeController', ['$sse' , function($sse) {
$sse.addEventSource('jobserveur', '/streams/jobserveur');
$sse.addEventListener('jobserveur', 'monitoring-event', function(e) {
var js = JSON.parse(e.data);
}
}]);
From here, make sure your app still work before moving onto the testing
Mock the app.sse module in your test
describe('SSE Fixture', function() {
beforeEach(function() {
browser.addMockModule('app.sse', function() {
angular.module('app.sse', []).value('$sse', {
addEventSource: function(name, url) {
},
addEventListener: function(name, event, callback) {
}
});
});
}
And you're done ! Obviously, the two methods are not implemented here nor is the app.sse module in anyway robust but you get the picture.
Hope it helps anyone
Cheers

Async loading a module property

I've defined a module (module1) which is supposed to load the value of a property asynchronously. How can I use this property in my app as soon as it is defined and only after it is defined?
My setup (simplified)
v1
app.js
require(['module1'], function(mod) {
document.getElementById("greeting").value = mod.getPersonName();
});
module1.js
define(['jquery'], function($) {
_person;
$.get('values/person.json')
.done(function(data) {
_person = data
});
return {
getPersonName: function() { return _person.name; }
}
values/person.json
{ name: 'John Doe', age: 34 }
This only works if the GET happens nearly instantaneously, otherwise it fails because _person is undefined when getPersonName is called.
v2
To counter this, I figured I would register a callback to notify the app when person was loaded.
app.js
require(['module1'], function(mod) {
mod.onPersonLoaded(function() {
document.getElementById("greeting").value = mod.getPersonName();
});
});
module1.js
define(['jquery'], function($) {
_person;
_onLoaded;
$.get('values/person.json')
.done(function(data) {
_person = data;
_onLoaded();
});
return {
getPersonName: function() { return _person.name; },
onPersonLoaded: function(cb) { _onLoaded = cb; }
}
}
This works if the GET is slow, however, if it's quick _onLoaded is undefined when .done() is called.
Is there a good way to use _person values in app.js as soon as they are defined and only once they are defined?
I'm using RequireJS, but my question is generally applicable to AMD.
Edit
In simplifying my example, I removed a layer which may be important. I'm using RactiveJS for the UI.
Setup (slightly less simplified)
app.js
require(['Ractive', 'module1'], function(Ractive, mod) {
var ractive = new Ractive({
...
data : {
name: mod.getPersonName()
}
});
ractive.observe(...);
ractive.on(...);
});
Edit 2
My current solution, subject to change. Register a callback that notifies app.js when person is loaded. Callback is called immediately if person is already loaded when callback is registered.
app.js
require(['Ractive', 'module1'], function(Ractive, mod) {
var ractive = new Ractive({
...
data : {}
});
mod.watchPerson(function() {
ractive.set('person.name', mod.getPersonName());
});
ractive.observe(...);
ractive.on(...);
});
module1.js
define(['jquery'], function($) {
_person;
_onLoaded;
$.get('values/person.json')
.done(function(data) {
_person = data;
try {
_onLoaded();
} catch (e) {
// that was fast!
// callback will be called when it is registered
});
return {
getPersonName: function() { return _person.name; },
watchPerson: function(cb) {
_onLoaded = cb;
if(_person != null) {
_onLoaded();
}
}
}
}
Promises are a good choice here because callbacks are always called asynchronously - you never encounter that confusing situation where _onLoaded() gets called before it's designed.
Unfortunately, jQuery's promise implementation doesn't adhere to the Promises/A+ specification, so you don't get that guarantee. If possible, you could use an alternative AJAX library like Reqwest, and do something like
app.js
define(['module1'], function (mod) {
mod.then(function(person) {
// do something with person.name
}
});
module1.js
define(['reqwest'], function (reqwest) {
return reqwest('values/person.json');
});
Using the text loader plugin
Another option, since you're already using AMD, would be to use a loader plugin, such as text:
app.js
define(['module1'], function (person) {
// do something with person.name
});
module1.js
define(['text!values/person.json'], function (personJSON) {
return JSON.parse(personJSON);
});
Using the text loader plugin
In fact there's even a JSON plugin, so you could do away with module1 entirely in this example situation:
app.js
define(['json!values/person'], function (person) {
// do something with person.name
});
This is how I would do this. Basically, it is not much different from your V2, but it adds more incapsulation.
app.js
require(['module1'], function(mod) {
mod.loadPerson(function(person) {
document.getElementById("greeting").value = person.getPersonName();
});
});
module1.js
define(['jquery'], function($) {
return {
loadPerson : function(callback) {
$.get('values/person.json').done(function(data) {
_person = data;
callback({
getPersonName: function() { return _person.name; }
});
});
}
}
}
You may also use promises promises instead of simple callback.

Categories