I have a protractor test that uses mailinator for check if I am receiving some mails but I would like to use Gmail instead.
My test looks like this:
In my down-mail.js:
function findEmailBySubject(subject) {
console.log("searching");
var emails = element.all(by.repeater('email in emails')).all(by.binding('email.subject'));
var theOne;
emails.map(function (item) {
return item.getText();
}).then(function (names) {
for (var i = 0; i < names.length; i++) {
console.log(names[i]);
//console.log(theOne);
if (names[i].indexOf(subject) != -1) {
theOne = i;
console.log('Found alert email in position: ' + theOne);
}
}
// the email should be in the list:
expect(theOne).not.toBeUndefined();
});
}
function deleteAlertEmails() {
console.log('Deleting all emails');
var flow = protractor.promise.controlFlow()
var emails;
emails = element.all(by.repeater('email in emails')).all(by.binding('email.subject'));
emails.count().then(function(count) {
console.log(count);
for(var i=0; i<count; i++) {
browser.waitForAngular();
browser.driver.sleep(1000);
emails = element.all(by.repeater('email in emails')).all(by.binding('email.subject'));
emails.map(function (email) {
return email;
}).then(function (items) {
items[0].click();
// and some more waits after the click...
browser.waitForAngular();
browser.driver.sleep(2000);
element(by.partialButtonText('Delete')).click();
});
}
});
}
describe('Referee', function() {
it('should send an email notification on failure of a check', function() {
var flow = protractor.promise.controlFlow()
var s3 = new AWS.S3();
// start by deleting all old mails:
console.log("0. First we delete all emails from the inbox");
deleteAlertEmails();
// First delete the file that is in S3, so the check will fail
console.log("1. Now delete the file from S3");
flow.await(deleteFile(s3)).then(function() {
console.log('File deleted');
// Wait for 1.5 minute to give it time to see that the file is not there and send a mail
console.log("waiting for the DOWN mail...");
// using browser.wait(condition)
flow.await(browser.driver.sleep(60000)).then(function() {
console.log("waited");
// wait for angular:
browser.waitForAngular();
console.log("angular ready");
// Search for the alert email:
console.log("2. Search for the alert email");
findEmailBySubject("DOWN - An S3 test file");
// Now put the file back:
console.log("3. Now put the file back");
flow.await(uploadFile(s3)).then(function() {
console.log("Successfully uploaded data to " + BUCKET_NAME + "/" + FILE_NAME);
// // wait 15 seconds
// browser.driver.sleep(15000);
console.log("waiting for the UP mail...");
// wait to make sure the UP email is sent
flow.await(browser.driver.sleep(60000)).then(function() {
// Search for the alert email:
console.log("4. Search for the UP email");
findEmailBySubject("UP - An S3 test file");
// and now delete all the alert emails:
console.log("5. Now delete all the emails from the inbox");
deleteAlertEmails();
});
}, function(err) {
console.log("ERROR uploading file to S3");
throw new Error(err);
});
});
}, function(err) {
console.log('ERROR deleting file - stopping here');
console.log(err);
throw new Error(err);
});
});
});
This is my local-config.js file:
exports.config = {
seleniumAddress: '',
specs: ['down-mail.js'],
onPrepare: function() {
browser.driver.get('http://www.mailinater.com/inbox.jsp?to=juanazensie');
},
jasmineNodeOpts: {
onComplete: null,
isVerbose: true,
showColors: true,
includeStackTrace: true,
defaultTimeoutInterval: 360000
}
};
I would like to know please if is it possible to do this with the Gmail API and read these mails from Gmail using Protractor?
Thank you very much!!!
Related
I'm using ngCordova File Transfer plugin in an ionic project to download set of images from urls. Here is the code i'm using for that.
// Save a image file in a given directory
$scope.saveImage = function(dir,imgUrl,imageName) {
var url = imgUrl;
var targetPath = cordova.file.dataDirectory+ dir+"/" + imageName;
var trustHosts = true;
var options = {};
// Download the image using cordovafiletransfer plugin
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function(result) {
$scope.loadedCount ++;
$ionicLoading.show({template : "<ion-spinner class='spinner-energized'></ion-spinner><p> Downloading pages : "+ $scope.loadedCount+" of "+ $scope.pages.length+ "</p><p>Please wait...</p><p><button class=\"button button-block button-positive\">continue in background</button></p>"});
if($scope.loadedCount == $scope.pages.length) {
$ionicLoading.hide();
$scope.showDownloadSuccessAlert = function() {
var alertPopup = $ionicPopup.alert({
title: 'Success!',
template: "Your magazine successfully downloaded. You can view it on Downloads!"
});
};
$scope.showDownloadSuccessAlert();
}
}, function(err) {
alert(JSON.stringify(err));
}, function (progress) {
if($scope.loadedCount > 80) {
}
});
};
// Download the current magazine
$scope.downloadMagazine = function() {
if($rootScope.user.user_id == undefined) {
$scope.showLoginAlert = function() {
var alertPopup = $ionicPopup.alert({
title: 'Oops!',
template: "Your must login to download magazines"
});
};
$scope.showLoginAlert();
return;
}
document.addEventListener('deviceready', function () {
var dirName = $rootScope.currentIssue.slug+'_VOL_'+$rootScope.currentIssue.vol+'_ISU_'+$rootScope.currentIssue.issue;
// First create the directory
$cordovaFile.createDir(cordova.file.dataDirectory, dirName, false)
.then(function (success) {
var count = 1;
$scope.loadedCount = 0;
angular.forEach($scope.pages, function(value, key) {
var imgName = count+".png";
$scope.saveImage(dirName,value.link,imgName); // Then save images one by one to the created directory.
count++;
});
}, function (error) {
// Directory already exists means that the magazine is already downloaded.
$scope.showDownloadedAlert = function() {
var alertPopup = $ionicPopup.alert({
title: 'Why worry!',
template: "Your have already downloaded this magazine. You can view it on downloads"
});
};
$scope.showDownloadedAlert();
});
}, false);
};
})
Problem here is that program try to download everything at once without waiting for previous one to finish. How to wait for one file to finish downloading and then start the other?
Thanks
If you want to do that automatically (you're not the first one : How can I execute array of promises in sequential order?), you could try reducing the list of address to a single Promise that will do the whole chain.
$scope.pages.reduce(function (curr,next) {
return curr.then(function(){
return $scope.saveImage(dirName, curr.link, imgName);
});
}, Promise.resolve()).then(function(result) {
$ionicLoading.show({template : "<ion-spinner class='spinner-energized'></ion-spinner><p> Downloading pages : "+ $scope.loadedCount+" of "+ $scope.pages.length+ "</p><p>Please wait...</p><p><button class=\"button button-block button-positive\">continue in background</button></p>"});
if($scope.loadedCount == $scope.pages.length) {
$ionicLoading.hide();
$scope.showDownloadSuccessAlert = function() {
var alertPopup = $ionicPopup.alert({
title: 'Success!',
template: "Your magazine successfully downloaded. You can view it on Downloads!"
});
};
$scope.showDownloadSuccessAlert();
}
});
And don't forget to make your saveImage async which returns a promise.
UPDATE:
You will need to remove the then logic from your save method and return the download method call:
return $cordovaFileTransfer.download(url, targetPath, options, trustHosts).promise;
Then you can put your download handler into Promise.resolve()).then. See above.
There's no other way other than chaining your promises. Here's an example:
angular.module('app', [])
.service('fakeDownloadService', function($timeout) {
this.download = (file) => $timeout(() => file, 100);
return this;
})
.run(function($rootScope, $q, fakeDownloadService) {
var listOfFiles = [];
for (var i = 0; i < 10; i++)
listOfFiles.push('file' + i);
$rootScope.log = [];
$rootScope.download = () => {
listOfFiles
.reduce((prev, curr) => {
return prev.then((result) => {
if(result)
$rootScope.log.push(result + ' downloaded');
return fakeDownloadService.download(curr);
});
}, $q.resolve())
.then(() => $rootScope.log.push('all done'));
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
<div ng-app="app">
<button ng-click="download()">Start</button>
<div>Log:</div>
<ul>
<li ng-repeat="entry in log track by $index">
{{entry}}
</li>
</ul>
</div>
I want to upload 4 images from an ionic app to server side made using sails js.
An user can upload many images so before submit a form so I save all images in an array as its shown below
var cameraOptions = {
quality: 100,
destinationType: Camera.DestinationType.NATIVE_URI,
sourceType : Camera.PictureSourceType.CAMERA,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 500,
targetHeight: 500,
popoverOptions: CameraPopoverOptions,
saveToPhotoAlbum: false,
allowEdit:true
};
var success = function(data){
$mdDialog.hide();
if(key==null)
{
compteurImage =compteurImage+1;
$scope.$apply(function () {
$scope.imgURI.push(data);
});
$scope.nombreImage=compteurImage;
}
else
{
$scope.$apply(function () {
$scope.imgURI[key]=data;
});
}
$rootScope.image=$scope.imgURI;
};
After having had all the images in an array, I loop on the array and I send each image to the server as shown below
for (var i = 0; i<$rootScope.image.length; i++) {
if (keepGoing) {
var options = new FileUploadOptions();
var params = {};
params.idArticle =response.article.idArticle;
var url=$rootScope.image[i].substr($rootScope.image[i].lastIndexOf('/') + 1);
options = {
fileKey: "file",
fileName:i+(url.split('?')[0]),
mimeType: "image/png",
idArticle: response.article.idArticle
};
options.params=params;
var failed = function (err) {
console.log(err);
keepGoing = false;
};
var success = function (result) {
count++;
if(count==$rootScope.image.length)
{
console.log("success");
}
};
var ft = new FileTransfer();
ft.upload($rootScope.image[i], Globals.urlServer + Globals.port + "/article/uploadImage", success, failed, options);
}
Server side the controller in charge of upload image is /article/uploadImage
uploadImage:function(req,res)
{
req.file('file')
.upload({ dirname: '../../assets/imagesArticle'},function (err, uploadedFiles) {
if (err) return res.serverError(err);
else {
var chemin = '';
var type = '';
uploadedFiles.forEach(function (file) {
chemin = require('path').basename(file.fd);
type = file.type;
Image.create({cheminImage:chemin, typeImage:type,article:req.body.idArticle}).exec(function(err,image){
if (err)
{
res.send({success:false});
}
if(image)
{
res.send({success:true});
}
})
});
}
});
},
My issue is if regardless how many pictures I upload, when I look image directory on server side, images are always identical and correspond to the last image of the images array. For example if I upload 3 differents images, on server side I get 3 identicals images whose correspond to the third or last image in array.
how can I fix it ?
I have simple test doing login and trying to check if it's success:
describe('My Angular App', function () {
describe('visiting the main homepage', function () {
beforeEach(function () {
browser.get('/');
element(By.id("siteLogin")).click();
});
it('should login successfully', function() {
element(By.name("login_username")).sendKeys("test#email.com");
element(By.name("login_password")).sendKeys("testpass");
element(By.id("formLoginButton")).click().then(function() {
browser.getCurrentUrl().then(function(url){
expect(url).toContain("profile");
});
});
});
});
});
It goes well until that last part where I'm checking URL, and in Selenium Server I get:
INFO - Executing: [execute async script: try { return (function (rootSelector, callback) {
var el = document.querySelector(rootSelector);
try {
if (window.getAngularTestability) {
window.getAngularTestability(el).whenStable(callback);
return;
}
if (!window.angular) {
throw new Error('angular could not be found on the window');
}
if (angular.getTestability) {
angular.getTestability(el).whenStable(callback);
} else {
if (!angular.element(el).injector()) {
throw new Error('root element (' + rootSelector + ') has no injector.' +
' this may mean it is not inside ng-app.');
}
angular.element(el).injector().get('$browser').
notifyWhenNoOutstandingRequests(callback);
}
} catch (err) {
callback(err.message);
}
}).apply(this, arguments); }
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]])
and also I get:
Failures:
1) My Angular App visiting the main homepage should login successfully
Message:
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
My protractor-conf.js:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
baseUrl: 'http://localhost:8080/Mysite',
capabilities: {
'browserName': 'firefox' // muste use firefox because I can't get .click() to work in Chrome
},
specs: [
'spec-e2e/*.js'
],
framework: 'jasmine2',
jasmineNodeOpts: {
isVerbose: true,
showColors: true,
defaultTimeoutInterval: 30000
}
};
I appreciate any help on this one.
Thanks
Looks like there is a non-Angular page opened after a click. If this is the case, you need to turn the synchronization between Protractor and Angular off:
afterEach(function () {
browser.ignoreSynchronization = false;
});
it('should login successfully', function() {
element(By.name("login_username")).sendKeys("test#email.com");
element(By.name("login_password")).sendKeys("testpass");
browser.ignoreSynchronization = true;
element(By.id("formLoginButton")).click().then(function() {
expect(browser.getCurrentUrl()).toContain("profile");
});
});
Note that you don't need to explicitly resolve the promise returned by getCurrentUrl and can let the expect() do that for you implicitly.
You may also need to wait for the URL to change:
var urlChanged = function(desiredUrl) {
return browser.getCurrentUrl().then(function(url) {
return url == desiredUrl;
});
};
browser.wait(urlChanged("my desired url"), 5000);
What is wrong with my code:
var emailExistence = require('email-existence');
var emails = ['klevisi#gmail.com', 'workingemail#gmail.com'];
var validEmails = [];
emails.forEach(function(email) {
emailExistence.check(email, function(err, res) {
if(res == true) {
validEmails.push(email); //No email is being added
console.log(email); //Emails are written to the console
}
});
});
validEmails.forEach(function(email) {
console.log(email); //Nothing is written to the console
});
The validEmails array isn't being populated.
It is because
validEmails.forEach(function(email) {
console.log(email); //printed at last
});
is outside the callback.So it executed before executing the callback.You will have to use validEmails after every thing has been added or all callback completed.
You can use underscore's after for these kind of things.
you can try with
var _U = require('underscore');
var afterAllEmailChecks = _U.after(emails.length,function(){
validEmails.forEach(function(email) {
console.log(email); //Nothing is written to the console
});
});
emails.forEach(function(email) {
emailExistence.check(email, function(err, res) {
if(res == true) {
validEmails.push(email); //No email is being added
console.log(email); //Emails are written to the console
}
afterAllEmailChecks();
});
});
I have a problem with handling the multiple timeouts in displaying the alert messages. In my app i get several alert messages when create a task, play the task, pause the task and delete a task. I set the timeout for all alerts as 5000 using $timeout().
This is the code for creating a task::
$scope.create = function () {
console.log('Taskkkkkkkkkk Title create function is called : ');
for (var i = 0; i < $scope.tasks.length; i++) {
if ($scope.tasks[i].title === this.title) {
$scope.duplicateTitle = true;
return;
}
}
var task = new Tasks({
'title': this.title,
'description': this.description,
'duration': 0,
'lastStart': '',
'archive': false,
'active': true
});
console.log('Taskkkkkkkkkk Title : ' + task.title);
if (task.title) {
task.$save(function (response) {
$scope.alerts.push({
type: 'success',
msg: 'Task have been Added!!' + '   <button type="button" class="close" data-dismiss="alert" ng-click="closeAlert()">×</button>'
});
$scope.closeAlert = function (index) {
$scope.alerts.splice(index, 1);
};
$timeout(function () {
$scope.alerts.splice($scope.alerts.indexOf(alert), 1);
}, 5000);
$scope.tasks.unshift(response);
//$scope.tasks = Tasks.query();
$scope.title = '';
$scope.description = '';
$state.go('listTasks');
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
} else {
var message = 'Title cannot be blank';
$scope.error = message;
}
};
But When i click the multiple tasks within 5sec, the last task alert message will de disappearing. But not the first one, means it is folling the stack order i.e., FIFO principle. I am writing the alert messages in the controllers.
I want the tasks to be disappeared in the order which they are arised. Any suggestions will be more helpful to me.
There in the timeout i just added the index value for the splice function.
$timeout(function () {
$scope.alerts.splice(index, 1);
}, 5000);
its working fine now...