This is the code that I have in the afterEach block.
afterEach(function() {
jasmine.getEnv().addReporter(new function () {
this.specDone = function (result) {
console.log("result is :"+result);
if (result.failedExpectations.length > 0) {
browser.takeScreenshot().then(function(png) {
console.log("png is :"+png);
console.dir(png);
var stream = fs.createWriteStream(specName.description+".png");
var stream2 = fs.createWriteStream(specName.description+"2.png");
stream.write(new Buffer(png,'utf8', function (err)
{
if (err) throw err
console.log('File saved.')
}));
stream2.write(new Buffer(png,'base64'));
stream.end();
stream2.end();
});
}
};
});
But none of the photo viewers is able to open the files. Any insights as to what is going wrong is highly appreciated.
System is windows 10 and browser Firefox 46.*
The console.log of the png returned by the browser.takeScreenshot() is as below:
png is :{"name":"screenshot","sessionId":"c18f3e08-9da0-4c71-9a10-391bab714e7a","status":0,"value":"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
I am not sure why takeShotshot() method returns the entire JSON object instead of just the base64 value for the screenshot. In your case, you can check whether the object returned by takeScreenShot methods contains any key with name value. If value is is present, then use it to get base64 value of the screenshot.
browser.takeScreenshot().then(function(png) {
var base64Value = png.hasOwnProperty("value") ? png.value : png;
var stream = fs.createWriteStream(specName.description+".png");
var stream2 = fs.createWriteStream(specName.description+"2.png");
stream.write(new Buffer(png,'utf8', function (err)
{
if (err) throw err
console.log('File saved.')
}));
stream2.write(new Buffer(base64Value,'base64'));
stream.end();
stream2.end();
})
Related
I am using Laravel, and trying add browser to browser audio calling. I am using Vonage (Tookbox) API for this, but I am getting some error.
here is my code:
async function audioCall() {
var publisher;
var targetElement = 'publisher';
var pubOptions = {publishAudio:true, publishVideo:false};
publisher = OT.initPublisher(targetElement, pubOptions, function(error) {
if (error) {
alert("The client cannot publish.");
} else {
console.log('Publisher initialized.');
}
});
// Setting an audio source to a new MediaStreamTrack
const stream = await OT.getUserMedia({
videoSource: null
});
const [audioSource] = stream.getAudioTracks();
publisher.setAudioSource(audioSource).then(() => console.log('Audio source updated'));
// Cycling through microphone inputs
let audioInputs;
let currentIndex = 0;
OT.getDevices((err, devices) => {
audioInputs = devices.filter((device) => device.kind === 'audioInput');
// Find the right starting index for cycleMicrophone
audioInputs.forEach((device, idx) => {
if (device.label === publisher.getAudioSource().label) {
currentIndex = idx;
}
});
});
const cycleMicrophone = () => {
currentIndex += 1;
let deviceId = audioInputs[currentIndex % audioInputs.length].deviceId;
publisher.setAudioSource(deviceId);
};
}
This code return an error on console:
Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules
I believe the issue is that you have
device.kind === 'audioInput'
and I'm pretty sure device.kind comes out like 'audioinput' (all lowercase).
examples:
https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo/kind
https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices#examples
That would make audioInputs empty (try to console.log it to verify) and gives you the error because there is no device.
Try:
device.kind.toLowerCase() === 'audioinput'
Hope it works out.
I´m having a hard time understanding how to perform this action(as the title says), and maybe someone could help me understand the process, my code is below:
My home-view-model:
var Observable = require("data/observable").Observable;
var ObservableArray = require("data/observable-array").ObservableArray;
var http = require("http");
function createViewModel() {
http.getJSON("http://myJsonfile").then(function (r) {
var arrNoticias = new ObservableArray(r.data);
return arrNoticias;
}, function (e) {
});
}
exports.createViewModel = createViewModel;
I have done a console.log of the arrNoticias before i have putted it inside a callback function and it returns [object object] etc...and then i have done this:
console.log(arrNoticias.getItem(0).titulo);
and it returns the info i need!.
Then in my home.js file i have this:
var observableModule = require("data/observable")
var ObservableArray = require("data/observable-array").ObservableArray;
var arrNoticias = require('./home-view-model.js');
console.log(arrNoticias.getItem(0).titulo);
and the result in the console is:
TypeError: arrNoticias.getItem is not a function. (In 'arrNoticias.getItem(0)', 'arrNoticias.getItem' is undefined)
My question is, how does this action is perform? passing the data from view-model to the .js file?
Thanks for your time
Regards
As that function send a URL request so probably it's an async function, which is on hold while requesting so that's why you get undefined. Normally, you will want your function that sends a URL request to return a promise. Based on that promise, you will the result as expected after the request is done. So:
function createViewModel() {
return new Promise<>((resolve, reject) => {
http.getJSON("http://myJsonfile").then(function (r) {
var arrNoticias = new ObservableArray(r.data);
resolve(arrNoticias);
}, function(e) {
reject(e);
});
}), (e) => {
console.log(e);
})
}
In home.js:
var homeVM= require('./home-view-model.js');
var arrNoticias;
homeVM.createViewModel().then(function(r) {
arrNoticias = r;
});
I would like to know if I am missing anything with regard to sinon.js I have tried using sinon.stub().returns and yields but am unable to get the result. Any pointers would be helpful
I have a module which calls another module that returns the value from the DB
var users = require('/users');
module.exports.getProfileImage = function (req, res) {
var profile = {};
else {
users.findOne("email", req.session.user.email, function (err, user) {
if (err) {
res.status(400).send();
}
else if (!user) {
//return default image
}
else if (user) {
//Do some other logic here
}
});
};
I am using mocha as the testing framework and am also using sinon. The problem that I am facing is when i create a stub of users.findOne to return a value the control does not come to my else if (user) condition.
my unit test case is as follows
describe("Return image of user",function(){
var validRequest = null;
validRequest={
session:{
user:{
email:'testUser#test.com',
role:'Hiring Company'
}
}
};
it("Should return an image from the file if the user is present in db",function(done){
var findOneUserResponse ={
companyName:"xyz",
email:"xyz#abc.com"
};
var findOne = sinon.stub(mongoose.Model, "findOne");
findOne.callsArgWith(1,null,findOneUserResponse);
user.getProfileImage(validRequest,response);
var actualImage = response._getData();
findOne.restore();
done();
};
};
So I went through the sinon.js documentation http://sinonjs.org/docs/ and came across what I was missing
describe("Return image of user",function(){
var validRequest = null;
validRequest={
session:{
user:{
email:'testUser#test.com',
role:'Hiring Company'
}
}
};
it("Should return an image from the file if the user is present in db",function(done){
var findOneUserResponse ={
companyName:"xyz",
email:"xyz#abc.com"
};
var findOne = sinon.stub(mongoose.Model, "findOne",function(err,callback){
callback(null,findOneUserResponse);
)};
user.getProfileImage(validRequest,response);
var actualImage = response._getData();
findOne.restore();
done();
};
};
I'm using Parse to represent the state of a beer keg (among other things). I'd like to check the user's notifications, stored in a "Notifications" table, to see if they'd like to receive a notification when the keg is filled.
I have all of the logic for setting the user's notification settings as well as sending notifications in cloud/notifications.js. All of the logic for updating the keg is in cloud/beer.js. I created an exported function called "sendKegRefillNotification" which performs a query.find() on the Notifications table and gets called from beer.js.
The problem is that it doesn't seem to be executing query.find() when I call the function from beer.js, however when I call the same function from a job within notifications.js, it works just fine.
main.js:
require("cloud/beer.js");
require("cloud/notifications.js");
beer.js:
var notify = require("cloud/notifications.js");
var Keg = Parse.Object.extend("Keg");
var fillKeg = function(beerName) {
var promise = new Parse.Promise();
var keg = new Keg();
keg.set("beerName", beerName)
keg.set("kickedReports", []);
keg.save(null, { useMasterKey: true }).then(function(keg) {
console.log("Keg updated to " + beerName + ".");
promise.resolve(keg);
notify.sendKegRefillNotification(keg);
},
function(keg, error) {
promise.reject(error);
});
return promise;
}
Parse.Cloud.define("beerFillKeg", function(request, response) {
var beerName = request.params.name;
if (!beerName) {
response.error("No beer was specified.");
return;
}
if (!util.isUserAdmin(request.user)) {
response.error("User does not have permission to update the keg.");
return;
}
fillKeg(beerName).then(function(keg) {
kegResponse(keg).then(function(result) {
response.success(result);
});
},
function(error) {
response.error(error);
});
});
function kegResponse(keg) {
var promise = new Parse.Promise();
var result = {
id: keg.id,
beer: {
name: keg.get("beerName")
},
filled: keg.createdAt,
kickedReports: []
};
var kickedReports = keg.get("kickedReports");
if (!kickedReports || kickedReports.length == 0) {
promise.resolve(result);
} else {
util.findUsers(kickedReports).then(function(users) {
result.kickedReports = util.infoForUsers(users);
promise.resolve(result);
}, function(users, error) {
console.log(error);
promise.resolve(result);
});
}
return promise;
}
notifications.js:
var Keg = Parse.Object.extend("Keg");
var Notification = Parse.Object.extend("Notifications");
exports.sendKegRefillNotification = function(keg) {
var beerName = keg.get("beerName");
console.log("Sending notifications that keg is refilled to '" + beerName + "'.");
var promise = new Parse.Promise();
var query = new Parse.Query(Notification);
query.include("user");
query.equalTo("keg_filled", true);
query.find({ useMasterKey: true }).then(function(notifications) {
console.log("Found notifications!");
promise.resolve("Found notifications!");
},
function(notifications, error) {
console.error("No notifications");
console.error(error);
promise.reject(error);
});
return promise;
}
Parse.Cloud.job("beerSendRefillNotification", function(request, status) {
var query = new Parse.Query(Keg);
query.descending("createdAt");
query.first().then(function(keg) {
if (!keg) {
status.error("No keg");
return;
}
exports.sendKegRefillNotification(keg);
},
function(keg, error) {
response.error(error);
});
});
When I run the job "beerSendRefillNotification" from the Parse dashboard, I can tell that query.find() is getting called because it prints "Found notifications!":
E2015-02-23T06:59:49.006Z]v1564 Ran job beerSendRefillNotification with:
Input: {}
Result: success/error was not called
I2015-02-23T06:59:49.055Z]false
I2015-02-23T06:59:49.190Z]Sending notifications that keg is refilled to 'test'.
I2015-02-23T06:59:49.243Z]Found notifications!
However, when I call the cloud function "beerFillKeg", it isn't because it's not printing "Found notifications!" or "No notifications":
I2015-02-23T07:00:17.414Z]v1564 Ran cloud function beerFillKeg for user HKePOEWZvC with:
Input: {"name":"Duff"}
Result: {"beer":{"name":"Duff"},"filled":{"__type":"Date","iso":"2015-02-23T07:00:17.485Z"},"id":"olLXh0F54E","kickedReports":[]}
I2015-02-23T07:00:17.438Z]false
I2015-02-23T07:00:17.523Z]Keg updated to Duff.
I2015-02-23T07:00:17.525Z]Sending notifications that keg is refilled to 'Duff'.
I finally understand it. In sendKegRefillNotification, you're calling query.find({...}), then returning an object. That find is asynchronous, and you're doing nothing to wait for the result. I think you need to return the find function call, rather than an object you set within that method.
In other words, you're running along, leaving some async running code behind you.
Edit: I understand what you tried to do. It sort of makes sense. You defined a promise, and thought the caller would wait for the promise. The problem is, the promise is defined in an asynchronous block. It doesn't yet have any meaning at the moment the caller gets it.
It looks like Parse doesn't allow you to run a query from inside a callback from save(). When I moved "notify.sendKegRefillNotification(keg);" to outside of the callback, it worked.
var fillKeg = function(beerName) {
var promise = new Parse.Promise();
var keg = new Keg();
keg.set("beerName", beerName)
keg.set("kickedReports", []);
keg.save(null, { useMasterKey: true }).then(function(keg) {
console.log("Keg updated to " + beerName + ".");
console.log("Send notifications.");
promise.resolve(keg);
},
function(keg, error) {
promise.reject(error);
});
notify.sendKegRefillNotification(keg); // Now this works
return promise;
}
Can anyone shed some more light on why this worked?
I use sails.js to update stock data from difference variable. When I do, console.log(product.stock), the value is 4. But it seems product.save() function below is not executed because attribute stock still not changed to 4. I guess the problem is at promise. Anybody know how to fix this?
exports.updateProductStock = function (details) {
details.forEach(function( detail ) {
var findPrevDetailRule = {
invoice: detail.invoice,
product: detail.product.id
};
var createPrevDetailRule = {
invoice: detail.invoice,
product: detail.product.id,
quantity: detail.quantity
};
var requirementBeforeUpdateStock = [
PreviousDetail.findOne(findPrevDetailRule).sort('createdAt desc').then(),
PreviousDetail.create(createPrevDetailRule).then()
];
Q.all(requirementBeforeUpdateStock)
.spread(function( prevDetail, newPrevDetail ) {
var difference = detail.quantity - prevDetail.quantity;
return {
prevDetail: prevDetail,
difference: difference
};
})
.then(function( results ) {
Product.findOne(results.prevDetail.product).then(function(product) {
product.stock += results.difference;
// maybe this below is not execute
product.save();
console.log(product.stock);
});
})
});
Note: I use sails 0.10-rc8. Have tested with sails-mysql, sails-mongo, sails-postgres, but still same.
.save() accepts a callback with which you can report success/failure.
For example, you can repost back to the client (from the sails documentation) :
product.save(function (err) {
if (err) return res.send(err, 500);
res.json(product);
});
Depending on scope, you may need to pass res into your function
Alternatively, monitor success/failure in the console, eg ,
product.save(function (err) {
if (err) console.log('save error: ' + err);//assuming err to be a string
console.log('save success');
});
Should at least give you a clue as to what's going wrong.