$firebaseArray is empty with ionic - ionic-framework

I am trying to load data in firebase with $firebaseArray as:
var ref = new Firebase(FURL);
var eventRef = ref.child('event');
$scope.events= $firebaseArray(eventRef)
I have event data in my firebase. But my $scope.events returns:
[]
0: Object
$$added: ()
$$error: ()
$$getKey: ()
$$moved: ()
$$notify: ()
$$process: ()
$$removed: ()
$$updated: ()
$add: ()
$destroy: ()
$getRecord: ()
$indexFor: ()
$keyAt: ()
$loaded: ()
$ref: ()
$remove: ()
$save: ()
$watch: ()
length: 0__proto__: Array[0]
what is possible reason?

Possible Reason You are accessing data before it is is loaded.
You must wait till data is loaded, Rewrite your code this way:
var ref = new Firebase(FURL);
var eventRef = ref.child('event');
$scope.events = $firebaseArray(eventRef);
$scope.events.$loaded()
.then(function(){
// access events here;
});

Related

SocketCluster - `procedure` and `receiver` in a single loop

I am trying out SocketCluster for an app where I will need both RPC style as well as One way Event based communication. I am following the Basic Usage section https://socketcluster.io/docs/basic-usage/
If I include socket.procedure and socket.receiver in the same listener loop it won't invoke the event. I want to understand why it is like that.
Really appreciate any input that will clear-up the concept.
Thanks!
My Server Side/Node:
const http = require("http");
const finalHandler = require("finalhandler");
const socketCluster = require("socketcluster-server");
const serveStatic = require("serve-static");
let serve = serveStatic("public", {index: ["index.html"]});
let httpServer = http.createServer(function onfRequest(req, res) {
serve(req, res, finalHandler(req, res))
});
let agServer = socketCluster.attach(httpServer);(async () => {
for await (let {socket} of agServer.listener("connection")) {
// RPC
(async () => {
for await (let req of socket.procedure("customProc1")) {
console.log(`Received RPC request`);
req.end("Success");
}
})();
// Event (One Way)
(async () => {
for await (let data of socket.receiver("customEvent1")) {
console.log(`Received Invoke data: ${data}`);
}
})();
}
})()
httpServer.listen(8000, () => {
console.log(`Server Started On : ${new Date().getTime()}`);
});
On the Client side Index.html/JavaScript:
function fireAnEvent() {
socket.transmit("customEvent1", "My Data");
}
async function callRpc() {
await socket.invoke("customProc1", {greetings: "Hey there function!"});
}

Index out of bounds when using element.all(by.binding)

User flow: Search for a case >> Search for an item within that case >> expect returned number of results matches value
describe('Search', function () {
beforeEach(function () {
loginPage.signIn();
loginPage.login(username, password);
});
afterEach(function () {
homePage.logOut();
});
it('alecxes suggestion code', function () {
var presenceOfAll = function(elementArrayFinder) {
return elementArrayFinder.count().then(function (count) {
return count > 0;
});
};
homePage.searchForCase(test_case);
filterSearchMenu.searchWithinCase(search_argument);
var hits = element.all(by.binding('response.hits.total'));
browser.wait(presenceOfAll(hits), TIMEOUT);
expect(element.all(by.binding('response.hits.total')).count()).toEqual(4);
});
});
This fails with expected 4 but was 0
describe('Search', function () {
searchResultTotal = element(by.binding('response.hits.total'));
beforeEach(function () {
loginPage.signIn();
loginPage.login(username, password);
});
afterEach(function () {
homePage.logOut();
});
it('should be able to search', function () {
homePage.searchForCase(test_case);
filterSearchMenu.searchWithinCase(search_argument);
browser.wait(EC.visibilityOf(searchResultTotal), TIMEOUT).then(function () {
expect(element.all(by.binding('response.hits.total')).count()).toEqual(4);
});
});
});
This works but comes back with a warning that more then one element found for locator by.binding('response.hits.total').
describe('Search', function () {
beforeEach(function () {
loginPage.signIn();
loginPage.login(username, password);
});
afterEach(function () {
homePage.logOut();
});
it('should be able to search', function () {
homePage.searchForCase(test_case);
filterSearchMenu.searchWithinCase(search_argument);
browser.wait(EC.visibilityOf(element.all(by.binding('response.hits.total')).first()), TIMEOUT).then(function () {
expect(element.all(by.binding('response.hits.total')).count()).toEqual(4);
});
});
});
This Fails and throws an index out of bounds.
Second set of eyes and any help would be appreciated.
You can also solve it with a custom Expected Condition that would check if there are more than 0 elements matching a locator found:
var presenceOfAll = function(elementArrayFinder) {
return elementArrayFinder.count().then(function (count) {
return count > 0;
});
};
var hits = element.all(by.binding('response.hits.total'));
browser.wait(presenceOfAll(hits), TIMEOUT);
expect(element.all(by.binding('response.hits.total')).count()).toEqual(4);
I'm thinking visibilityOf doesn't like multiple elements. Try:
browser.wait(EC.visibilityOf(element.all(by.binding('response.hits.total')).first()), TIMEOUT);

Protractor test: browser.get clears sessionStorage

I'm having a really weird issue with my protractor test. I'm trying to set the right credentials directly on the sessionStorage, but the authentication service doesn't pick up on it. I've isolated it to the following script:
describe('The search', () => {
beforeAll(() => {
browser.executeScript(() => {
window.sessionStorage.setItem('something', JSON.stringify({"test":"test"}));
});
});
it('works when changing URL', () => {
var result1 = browser.executeScript('return window.sessionStorage.getItem(\'something\')');
browser.get('/');
var result2 = browser.executeScript('return window.sessionStorage.getItem(\'something\')');
expect(result1).toBe(result2);
});
});
The output:
1) The search works when changing URL
Message:
Expected '{"test":"test"}' to be null.
Stack:
Error: Failed expectation
at Object.<anonymous> (/source/search.spec.ts:12:25)
at process._tickCallback (node.js:368:9)
So as you can see, as soon as browser.get() is called, the sessionStorage is cleared. Does anyone have any idea on why this could be happening?
Navigating to the URL and then setting the local storage item worked for me:
describe('The search', function () {
var value = JSON.stringify({"test":"test"});
beforeAll(function () {
browser.get('/');
browser.executeScript(function (value) {
window.sessionStorage['something'] = value;
}, value);
});
it('works when changing URL', function () {
var result = browser.executeScript('return window.sessionStorage.getItem(\'something\');');
expect(value).toEqual(result);
});
});

When I isolate a test it passes, but when run sequentially with other tests it fails with NoSuchElementError

I was making some changes to the page objects we use for running our Protractor tests to run on Sauce Labs i.e., calling a utility method to get browser and platform so we can use the appropriate test user, and after making the change I kept getting a NoSuchElementError when running the test suite.
When I isolate the logout test, it passes, but when run in conjunction with any other files, it fails. Currently, I'm only running the login test and logout test on Chrome to limit the possible causes.
We use page objects to navigate to a testable state, in this case a login page object and a dashboard page object (logging in takes you to the dashboard).
The login page object:
'use strict';
var TestUtils = require('../../util/test-utils.js');
var HeaderPageElement = require('../page_elements/header-page-element.js');
var LoginPage = function () {
var self = this;
this.get = function () {
browser.get('http://localhost:9000/index.html');
this.header = new HeaderPageElement();
this.loginForm = element(by.name('loginForm'));
this.usernameInput = element(by.model('credentials.username'));
this.passwordInput = element(by.model('credentials.password'));
this.loginButton = element(by.name('loginButton'));
this.signupLink = element(by.xpath('//a[#ui-sref="signup"]'));
};
this.setCredentials = function (username, password) {
var deferred = protractor.promise.defer();
var testUtils = new TestUtils();
testUtils.getCapabilities().then(function (capabilities) {
return testUtils.getTestUser(capabilities.browserName, capabilities.platform);
}).then(function (testUser) {
username = username || testUser.username;
password = password || testUser.password;
self.usernameInput.sendKeys(username);
self.passwordInput.sendKeys(password);
deferred.fulfill();
});
return deferred.promise;
};
this.login = function (username, password) {
return this.setCredentials(username, password).then(function () {
return self.loginButton.click();
});
};
this.signup = function () {
return this.signupLink.click();
};
this.get();
};
module.exports = LoginPage;
The dashboard page object:
'use strict';
var LoginPage = require('./login-page.js');
var HeaderPageElement = require('../page_elements/header-page-element.js');
var ProjectCreateModalPageElement = require('../page_elements/project-create-modal-page-element.js');
var DashboardPage = function () {
var self = this;
this.get = function () {
var loginPage = new LoginPage();
loginPage.login();
this.header = new HeaderPageElement();
this.newProjectButton = element(by.name('newProjectButton'));
this.projectFilterInput = element(by.name('projectFilterInput'));
};
this.createNewProject = function (projectTitle, projectTypes) {
var deferred = protractor.promise.defer();
this.newProjectButton.click().then(function () {
var modalPage = new ProjectCreateModalPageElement();
modalPage.createNewProject(projectTitle, projectTypes);
deferred.fulfill();
});
return deferred.promise;
};
this.get();
};
module.exports = DashboardPage;
These are the tests that are being run.
The login test:
'use strict';
var LoginPage = require('./pages/login-page.js');
describe('login test', function () {
var page;
beforeEach(function () {
page = new LoginPage();
});
it('should be directed to login', function () {
expect(page.loginForm.isPresent()).toBe(true);
});
it('Login button should be disabled', function () {
expect(page.loginButton.getAttribute('disabled')).toEqual('true');
page.setCredentials('wrong', 'user').then(function () {
expect(page.loginButton.getAttribute('disabled')).toEqual(null);
});
});
it('login should fail and remain at login screen', function () {
page.login('wrong', 'user').then(function () {
expect(page.loginForm.isPresent()).toBe(true);
});
});
it('login success should redirect to dashboard', function () {
page.login().then(function () {
browser.wait(function () {
return $('#dashboard').isPresent();
});
expect($('#dashboard').isDisplayed()).toBe(true);
});
});
});
The logout test:
'use strict';
var DashboardPage = require('./pages/dashboard-page.js');
describe('logout test', function () {
var page;
beforeEach(function () {
page = new DashboardPage();
});
it('logout success should redirect to login page', function () {
page.header.logout().then(function() {
browser.wait(function () {
return $('#login').isPresent();
});
expect($('#login').isDisplayed()).toBe(true);
});
});
});
The error I get when running these tests sequentially is as follows:
NoSuchElementError: No element found using locator: by.model("credentials.username")
The line it specifies is the get method inside the DashboardPage object, whereby it instantiates a LoginPage object and calls the login method so as to navigate to the dashboard:
this.get = function () {
var loginPage = new LoginPage();
loginPage.login();
this.header = new HeaderPageElement();
this.newProjectButton = element(by.name('newProjectButton'));
this.projectFilterInput = element(by.name('projectFilterInput'));
};
For whatever reason, the usernameInput of the login page hasn't been set by the time the login method is called.
I'm quite sure it's got something to do with not having coded promises correctly, but I've been bashing my head against it for days without any success. Any help would be greatly appreciated.

Why do my socket.on calls multiply whenever i recenter my controller

I've been using the socket factory described here by the brian ford here
http://www.html5rocks.com/en/tutorials/frameworks/angular-websockets/
here is the factory
myApp.factory('socket', function ($rootScope) {
var socket = io.connect('url');
return {
on: function (eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
},
emit: function (eventName, data, callback) {
socket.emit(eventName, data, function () {
var args = arguments;
$rootScope.$apply(function () {
if (callback) {
callback.apply(socket, args);
}
});
})
}
};
});
I have a socket.emit in my controllers initialization function and whenever i reenter this controller from another page the receiving socket.on function executes +1 times. This happens until I manually refresh the page then it resets to 1. I don't explicitly store my socket in session. So what could be causing my socket.on to call multiple times.
Here is my socket.emt in my controller
this always executes once.
$scope.init = funciton (){
...
socket.emit('getSignedSlidesFromUrl', $scope.slideLocation);
}
Here is my socket.on that will be recieve 'getSignedSlidesFromUrl'
socket.on('signedUrls', function (signedSlides){
console.log('signedUrls socket hit');
$scope.slides = signedSlides;
console.log($scope.slides[0]);
console.log($scope.display);
});
Here is an example of my console log after reentering the controller
about to emit getSignedSlidesFromUrl from init controllers.js:71
display after called $scope.first slide is0 controllers.js:574
flash object is controllers.js:537
signedUrls socket hit controllers.js:816
0 controllers.js:823
signedUrls socket hit controllers.js:816
0 controllers.js:823
if I reenter the controller again my log would change to
signedUrls socket hit controllers.js:816
0 controllers.js:823
signedUrls socket hit controllers.js:816
0 controllers.js:823
signedUrls socket hit controllers.js:816
0 controllers.js:823
You have to add removeAllListeners to your factory (see below) and have the following code in each of your controllers:
$scope.$on('$destroy', function (event) {
socket.removeAllListeners();
});
Updated socket factory:
var socket = io.connect('url');
return {
on: function (eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
},
emit: function (eventName, data, callback) {
socket.emit(eventName, data, function () {
var args = arguments;
$rootScope.$apply(function () {
if (callback) {
callback.apply(socket, args);
}
});
})
},
removeAllListeners: function (eventName, callback) {
socket.removeAllListeners(eventName, function() {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
}
};
});
I tried #michaeljoser's solution, but it didn't work for me.
Then I found another solution and it worked
var socket = io.connect('url');
return {
on: function (eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
},
emit: function (eventName, data, callback) {
socket.emit(eventName, data, function () {
var args = arguments;
$rootScope.$apply(function () {
if (callback) {
callback.apply(socket, args);
}
});
})
},
getSocket: function(){
return socket;
}
};
});
And in controller, I called
$scope.$on('$destroy', function (event) {
socket.getSocket().removeAllListeners();
});