I have been working on a Jasmine custom matcher to check if a page is accessible.
The important bit looks like this:
var _result = {};
AxeBuilder(browser.driver).analyze(function(results) {
if (util.equals(results.violations.length, expected)) {
_result.pass = true;
_result.message = 'Selection was accessible.';
} else {
_result.pass = false;
_result.message = results.violations;
}
});
return result;
The problem I have is that _result (not results) is always an empty object.
I suspect the problem is that AxeBuilder(...).analyze(...) is async but does not return a promise.
My test is not being run from Karma it is initiated via my Protractor config.
If my suspicions are true, how would I go about wrapping it in a promise?
If possible, You should use WebDriverJS promises provided within protractor
function builder() {
return AxeBuilder(browser.driver).analyze(function(results) {
var deferred = protractor.promise.defer();
if (util.equals(results.violations.length, expected)) {
_result.pass = true;
_result.message = 'Selection was accessible.';
deferred.fulfill(_result);
} else {
_result.pass = false;
_result.message = results.violations;
deferred.reject(_result);
}
return deferred;
});
}
Here is how you could use it,
builder().then(function(_result) {
console.log(_result.pass);
}, function(err) {
console.error(err);
});
You can implement callback concept to prevent execution of statement 'return result' before result object is ready. You can try with below code.
var _result = {firstvalue:"test"};
AxeBuilder(browser.driver).analyze(function(results,callback) {
if (util.equals(results.violations.length, expected)) {
_result.pass = true;
_result.message = 'Selection was accessible.';
} else {
_result.pass = false;
_result.message = results.violations;
}
callback(result);
});
var callback=function(result){
return result;
}
Im not familiar with AxeBuilder. As u mentioned that AxeBuilder.analyze() is a async method, you need to return the _result variable inside the analyze method. Try the below code,
return AxeBuilder(browser.driver).analyze(function(results) {
if (util.equals(results.violations.length, expected)) {
_result.pass = true;
_result.message = 'Selection was accessible.';
} else {
_result.pass = false;
_result.message = results.violations;
}
return _result;
});
In your code you are returning the _resultvariable before the analyze method is executed.
Related
My app creates a new item, and I want to retrieve the key to use in a server script. The data variable returns null though. This is what I have:
function addItem(addButton) {
var addItemPage = addButton.root;
if (!addItemPage.validate()) {
return;
}
var props = addItemPage.properties;
var itemDs = addItemPage.datasource;
props.Creating = true;
itemDs.saveChanges({
success: function(key) {
props.Creating = false;
if (app.currentPage !== app.pages.EditItem) {
return;
}
var newProjectItem = itemDs.item;
newProjectItem._loadHistory();
gotoEditItemPage(newProjectItem._key, true);
return newProjectItem;
},
failure: function(error) {
props.Creating = false;
console.error(error);
}
});
gotoEditItemPage();
var data = app.datasources.ProjectItems.item._key;
google.script.run.withSuccessHandler(function(value){
alert("Created");
}).createDoco(data);
}
This is not neat by any means, but I fixed it by creating a new function:
function addItem(addButton, key) {
var addItemPage = addButton.root;
if (!addItemPage.validate()) {
return;
}
var props = addItemPage.properties;
var itemDs = addItemPage.datasource;
props.Creating = true;
itemDs.saveChanges({
success: function() {
props.Creating = false;
if (app.currentPage !== app.pages.EditItem) {
return;
}
var newProjectItem = itemDs.item;
newProjectItem._loadHistory();
gotoEditItemPage(newProjectItem._key, true);
var key = newProjectItem._key;
value(key);
},
failure: function(error) {
props.Creating = false;
console.error(error);
}
});
gotoEditItemPage();
function value(record){
var data = record;
google.script.run.withSuccessHandler(function(value){
alert("Created");
}).createDoco(data);
}
}
My case:
app.js:
let app = angular.module('myApp', []);
app.controller('login', function ($scope, $login) {
$scope.account = {};
$scope.loginForm_submit = function ($event, account) {
$event.preventDefault();
if ($login.isValid(account)) {
$login.submit(account);
// goal:
$login.submit(account).then(function () {
window.location = '/'
}, function (msg) {
console.log(msg)
});
}
};
});
login.js:
app.factory('$login', function () {
let o = {
isValid: function (x) {
let success = false;
// validating...
return success
},
submit: function (x) {
// prevent to force submitting
if (this.isValid(x)) {
let formData = new FormData(), xhttp = new XMLHttpRequest();
// appending data to 'formData' via 'x'...
xhttp.onreadystatechange = function () {
if (xhttp.readyState === XMLHttpRequest.DONE) {
let data = JSON.parse(xhttp.responseText);
if (data['Success']) {
// return then() with successCallback() function
} else {
let msg = data['ErrorMessage'];
// return then() with errorCallback() function
}
}
}
xhttp.open('POST', '/account/register');
xhttp.send(formData);
}
}
}
return o
});
data is an object like:
let data = {
'Success': false,
'ErrorMessage': 'Invalid login attempt.'
};
I want to return then() method after submitting to access result. How can I do that?
UPDATE:
In controller:
[HttpPost]
public async Task<ObjectResult> Login(LoginViewModel model)
{
IDictionary<string, object> value = new Dictionary<string, object>();
value["Success"] = false;
if (ModelState.IsValid)
{
// login
value["Success"] = true;
}
return new ObjectResult(value);
}
First of all, you should avoid using $ for your own functions.
About your problem, you need to use $q. And you should use what angular offers to you.
Let me give you this :
app.factory('loginFactory', function($q, $http) {
var ret = {
isValid: isValid,
submit: submit
}
return ret;
function isValid(x) {
// Your code ...
return false;
}
function submit(x) {
// x is your form data, assuming it's a JSON object
var deferred = $q.defer();
// Assuming you're posting something
$http.post('yoururl', x,{yourConfigAsAnObject: ''})
.then(function(success){
console.log(success.data);
deferred.resolve(success.data);
}, function(error) {
console.log(error);
deferred.reject(error);
});
return deferred.promise;
}
});
Now, in your controller, you can use
loginFactory.submit(yourParam).then(function(success){
// Your code
}, function(error) {
// Your code
});
app.factory('$login', function ($q) {
let o = {
isValid: function (x) {
let success = false;
// validating...
return success
},
submit: function (x) {
var d = $q.defer();
// prevent to force submitting
if (this.isValid(x)) {
let formData = new FormData(), xhttp = new XMLHttpRequest();
// appending data to 'formData' via 'x'...
xhttp.onreadystatechange = function () {
if (xhttp.readyState === XMLHttpRequest.DONE) {
let data = JSON.parse(xhttp.responseText);
if (data['Success']) {
// return then() with successCallback() function
d.resolve('success');
} else {
let msg = data['ErrorMessage'];
d.reject(msg);
// return then() with errorCallback() function
}
}
}
xhttp.open('POST', '/account/register');
xhttp.send(formData);
}
else {
d.reject('error');
}
return d.promise;
}
}
return o
});
dude,I made a sample function with promise
$q should be injected as dependency
class AppUserService {
constructor($http,CONFIG_CONSTANTS,$q, AuthService) {
this.API_URL = CONFIG_CONSTANTS.API_URL;
this.$http = $http;
this.$q = $q;
this.api_token = AuthService.api_token;
}
getAppUserList() {
const deferred = this.$q.defer();
this.$http.get(`${this.API_URL}/customer?api_token=${this.api_token}`)
.success(response => deferred.resolve(response))
.error(error => deferred.reject(error));
return deferred.promise;
}
}
its in ES6 form.
How to use:
AppUserService.getAppuserList().then(success => {
// code for success
},error => {
// code for error
})
submit: function (x) {
return $q(function (resolve, reject) {
// prevent to force submitting
if (this.isValid(x)) {
let formData = new FormData(), xhttp = new XMLHttpRequest();
// appending data to 'formData' via 'x'...
xhttp.onreadystatechange = function () {
if (xhttp.readyState === XMLHttpRequest.DONE) {
let data = JSON.parse(xhttp.responseText);
if (data['Success']) {
resolve(data);
// return then() with successCallback() function
} else {
let msg = data['ErrorMessage'];
reject(msg);
}
}
}
xhttp.open('POST', '/account/register');
xhttp.send(formData);
}
else
reject('x not valid');
}
}
}
But I recommended to use angular $http service.
I'm converting some IndexedDB code to use YDN-DB and need some help in converting this. This code essentially deletes the DB if the page is loaded or reloaded but not when it is refreshed.
How would I accomplish that using YDN-DB?
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
var db;
window.refreshing = false;
$(document).ready(function(){
if(window.performance) {
if(performance.navigation.type == 0 ) {
// The db already exists so delete it and re-create it so we don't have stale records.
deleteDB();
} else {
window.refreshing = true;
open();
}
}
});
function deleteDB() {
var request = indexedDB.deleteDatabase("DocsDB");
request.onsuccess = function() {
open();
}
request.onerror = function(event) {
throw "Error in deleteDB.";
}
}
function open() {
var request = indexedDB.open("DocsDB");
var upgraded = false;
request.onupgradeneeded = function(evt) {
upgraded = true;
var dbnew = evt.target.result;
dbnew.onerror = function(event) {
console.log("IndexedDB error: " + evt.target.error.code);
};
var objectStore = dbnew.createObjectStore(
"docs", { keyPath: "id", autoIncrement: true });
objectStore.createIndex("docname", "DOC_NAME", { unique: false });
objectStore.createIndex("printdate", "PRINT_DATE", { unique: false });
}
request.onsuccess = function(evt) {
db = request.result;
if (!upgraded && !window.refreshing) {
throw "Not upgraded";
}
request.result.onversionchange = function(e) {
if (e.newVersion === null) { // An attempt is made to delete the db
e.target.close(); // Manually close our connection to the db
}
};
if(typeof db != 'undefined' && !window.refreshing) {
// We load the store with the records here, attempting to add records via ajax doesn't work
// looks like we'll ahve to load them via ajax before initialization?
var store = getObjectStore(db);
for (i=0; i<documents["Rows"].length-1;i++) {
store.add(documents["Rows"][i]);
}
}
}
request.onerror = function() {
throw "Error in open";
}
}
function getObjectStore(db, mode = 'readwrite') {
if(typeof db != 'undefined') {
var tx = db.transaction('docs', mode);
return tx.objectStore('docs');
} else {
return null;
}
}
To delete a database use, ydn.db.deleteDatabase("DocsDB").
i have a problem.
I'm trying to build highcharts graphic.
How it works:
I'm going to my route ('ship.details'), and here i have not problems.
My problem:
subsription to (ships_snapshots_all) not working.
My publish.js:
Meteor.publish("ships_snapshots", function(user, options) {
if(!this.userId) return null;
if(this.userId) {
console.log('subsribed by ' + user);
return ships_snapshots.find({userId: user}, options);
}
});
Meteor.publish("ships_snapshots_all", function() {
return ships_snapshots.find({});
})
My subscribe.js (in lib folder):
Meteor.subscribe('ships_snapshots');
Meteor.subscribe('ships_snapshots_all');
Problem 100% in my subsription, because if i'm installing autopublish all working good. And problem in my router i think.
router.js:
Router.route('/ships/details', {
name: 'ship.details',
loadingTemplate: 'loading',
onBeforeAction: function() {
var shipId = Session.get('currentShipId');
if(!shipId) {
Router.go('user.ships');
} else {
this.next();
}
},
waitOn: function() {
if (Meteor.isClient) {
var getCompare = Meteor.user().profile.wows.compareWith;
console.log(getCompare);
var user2 = Meteor.users.findOne({"profile.wows.nickname": getCompare});
var user2Id = user2._id;
if (getCompare) {
var user2 = Meteor.users.findOne({"profile.wows.nickname": getCompare});
if (user2) {
var user2Id = user2._id;
}
}
if (getCompare) {
var handle = Meteor.subscribe('ships_snapshots', Meteor.user()._id) && Meteor.subscribe('ships_snapshots', user2Id) && Meteor.subscribe('userSearchInfo', getCompare);
Session.set('compareWith', user2);
console.log('user2 _____');
console.log(user2);
return handle
} else {
var handle = Meteor.subscribe('ships_snapshots', Meteor.user()._id) && Meteor.subscribe('ships_snapshots', user2Id);
return handle
}
}, data: function() {
if (handle.ready()) {
var shipname = this.params.shipName;
var obj = {};
var query = ships.findOne();
var shipId = Session.get('currentShipId');
var result;
_.each(Meteor.user().profile.wows.ships, function(row) {
if (row.ship_id === shipId) {
result = row;
}
});
return result;
}
}
});
I think my problem in subscripion for ship_snapshots. Something going wrong here, but i can't to resolve this problem.
What exactly do you mean by "not working"? From your code I would assume that you're always seeing all the ship snapshots.
You shouldn't have the subscribes in /lib if you have them in your router. If you have Meteor.subscribe('ships_snapshots_all'); in /lib then you should always be seeing all the ship snapshots (assuming you're not stopping that subscription anywhere).
Also your subscription to all should be:
Meteor.publish("ships_snapshots", function(user, options) {
if(this.userId) {
console.log('subsribed by ' + user);
return ships_snapshots.find({userId: user}, options);
} else this.ready();
});
You don't want to return null when there is no user, you can just mark the subscription as ready without finding any records. This is not the cause of your problem but just good practice.
Meteor.publish("ships_snapshots", function(user, options) {
if(!this.userId) return null;
if(this.userId) {
console.log('subsribed by ' + user);
return ships_snapshots.find({userId: user._id}, options);
}
});
In your publish script, is user really an id or is it a user object? I changed it to user._id. Please check that.
getTime: function () {
host="http://www.xxxxxx.com/";
res= Meteor.bindEnvironment(function(){
var Fiber = Meteor.require('fibers');
var Future = Meteor.require('fibers/future');
var future = new Future();
request(host, function (error, response, body) {
Fiber(function(){
if (!error && response.statusCode == 200) {
$ = cheerio.load(body);
var $thumbs = $('.thumb');
for (var i = 0, l = $thumbs.length ; i < l ; i++) {
// elements
var $thumb = $($thumbs[i]);
// save info
videourl=host+$thumb.find('a').attr('href');
videothumbs = [$thumb.find('img').attr('src')];
videos=Videos.insert({title:videoTitle,thumbs:videothumbs,lastUpdated:Date.now()});
}
return videos;
}
else {
return "error";
}
}).run()
});
}) ;
return res;
}
This is a server side method and returning undefined
Without bindenvironment it is returning error to use bindenvironemnt.
Am I using it properly, can somebody tell m the modifications in my code
You need a future to return the value of inner function:
Meteor.methods({
getTime: function() {
var future = new Future();
Meteor.bindEnvironment(function() {
future.return('Some value');
});
return future.wait();
},
});
Check out this Meteorpad for an example.
If you use suggestion from #saimeunt comment, then your code could be simplified into form:
SERVER:
Meteor.methods({
getSite:function(url){
var site = HTTP.get(url);
console.log("statusCode =\n " , site.statusCode);
console.log("content.length =\n ",site.content.length);
console.log("header =\n ",site.headers);
$ = cheerio.load(content);
...
}
})
CLIENT :
Meteor.call("getSite", "http://www.google.com");
See how it works