Protractor : Wait for element doesn't work in the 'second browser instance' of a same test - protractor

I am trying to use multiple browsers in the same test, script fails when i try to wait for the element present in second browser.
var browser2 = browser.forkNewDriverInstance(true);
browser2.get('https://test.app.com');
var EC = protractor.ExpectedConditions;
browser2.wait(EC.visibilityOf($('.meeting-btn>span')),15000); //Script fails here
browser2.$('.meeting-btn>span').click();
console.log("clicked Meeting button");
*Error:
Failed: Wait timed out after 15010ms
The element is actually present in the screen but wait keyword isn't locating the element. The script actually works when i write the code in following manner.
var browser2 = browser.forkNewDriverInstance(true);
browser2.get('https://test.app.com');
var EC = protractor.ExpectedConditions;
browser.sleep(15000);
browser2.$('.meeting-btn>span').click();
console.log("clicked Meeting button");
Script fails only when i insert wait keyword. Any suggestions would be helpful.

Your error is this line:
browser2.wait(EC.visibilityOf($('.meeting-btn>span')),15000); //Script fails here
Using $('.meeting-btn>span') implicitly uses the main browser so is equivalent to browser.$('.meeting-btn>span'), which can't be found in browser2.
To fix the error, use:
browser2.wait(EC.visibilityOf(browser2.$('.meeting-btn>span')),15000); //Script fixes
To avoid this kind of error during developpment, I usually define my ElementFinder first, then re-use it. See "targetElement" here:
var browser2 = browser.forkNewDriverInstance(true);
browser2.get('https://test.app.com');
const targetElement = browser2.$('.meeting-btn>span');
var EC = protractor.ExpectedConditions;
browser2.wait(EC.visibilityOf(targetElement),15000); //Script fails here
targetElement.click();
console.log("clicked Meeting button");
To test this code in a new project:
follow setup steps from https://www.protractortest.org/#/
change conf.js so it looks like the following:
exports.config = {
// seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['todo-spec.js'],
directConnect: true,
// SELENIUM_PROMISE_MANAGER: true
};
create test file test.js:
function checkElements(targetBrowser) {
const targetURL = 'https://angular.io/';
targetBrowser.get(targetURL);
const targetSelector = 'a.button.hero-cta.no-print';
const targetElem = targetBrowser.$(targetSelector);
var EC = protractor.ExpectedConditions;
targetBrowser.wait(EC.visibilityOf(targetElem),15000); //Script fails here
targetElem.click();
// title is present
const titleElem = targetBrowser.$("#getting-started-with-angular");
expect(titleElem.getText()).toEqual('Getting started with Angular');
}
describe('angular homepage', function() {
it('test with browser', function() {
checkElements(browser);
});
it('test with 2nd browser', function() {
const browser2 = browser.forkNewDriverInstance(true);
checkElements(browser2);
});
});
add another it method with the code from this answer:
it('MY TEST', function() {
var browser2 = browser.forkNewDriverInstance(true);
browser2.get('https://test.app.com');
const targetElement = browser2.$('.meeting-btn>span');
var EC = protractor.ExpectedConditions;
browser2.wait(EC.visibilityOf(targetElement),15000); //Script fails here
targetElement.click();
console.log("clicked Meeting button");
});
run protractor: "protractor conf.js"

Related

Protractor upload stuck when filesearch pops up

I'm trying to figure out what's wrong with the code below:
it('should upload a photo', function(){
var photo = './photos/et-test.jpeg',
exactPhoto = path.resolve(__dirname, photo);
var form = element(by.id('fileupload'));
var upload = element(by.css('input[type = "file"]'));
var addFiles = element(by.cssContainingText('.btn.btn-success.fileinput-button.mb-10','Add files...'));
var uploadBtn = element(by.css('.btn.btn-primary.start.mt-20'));
element(by.cssContainingText('.inline_link','Upload more album photos now')).click();
element(by.id('secondary_upload_link')).click();
browser.wait(EC.visibilityOf(addFiles), 5000);
addFiles.click();
upload.sendKeys(exactPhoto);
browser.wait(EC.visibilityOf(uploadBtn), 5000);
uploadBtn.click();
expect(element(by.css('.table')).getText()).toBe('Upload Finised');
});
I keep getting stuck on the filesearch popup and receive this error:
Message:
Failed: Wait timed out after 5006ms
Is there anything lacking or should've been done based on the flow of my code?
If I'm understanding your issue correctly you are seeing a popup window when uploading a file. Can you try the following capability in your conf (assuming you are using Chrome)
capabilities: {
browserName: 'chrome',
chromeOptions: {
prefs: {
download: {
'prompt_for_download': false,
'directory_upgrade': true,
'default_directory': 'src/test/javascript/e2e/downloads'(or where ever you prefer)
}
}
}
}
Yes, you don't need to click on it, just sendKeys() for this input element
Sometimes it needs to make this input visible. Just try like that (it works in my case for await/async protractor):
private addAttachment = element(by.css('input[type="file"]'))
await browser.executeScript("arguments[0].style.visibility = 'visible'; arguments[0].style.height = '1px'; arguments[0].style.width = '1px'; arguments[0].style.opacity = 1; arguments[0].style.display = 'inline'; arguments[0].style.overflow = 'visible'", this.addAttachment)
await browser.executeScript("arguments[0].focus();", await this.addAttachment.getWebElement())
await this.addAttachment.sendKeys(path)
Try this:
var photo = './photos/et-test.jpg',
exactPhoto = path.resolve(__dirname, photo);
var form = element(by.id('fileupload')); ///Users/leochardc/ET/photos/et-test.jpg
var upload = element(by.css('.fileupload_section input[type = "file"]'));
var addFiles = element(by.cssContainingText('.btn.btn-success.fileinput-button.mb-10','Add files...'));
var uploadBtn = element(by.css('.btn.btn-primary.start.mt-20'));
var uploadFinished = element(by.css('.fileupload_section .text-center p'));
browser.get(url);
element(by.cssContainingText('.inline_link','Upload more album photos now')).click();
element(by.id('secondary_upload_link')).click();
browser.wait(EC.visibilityOf(addFiles), 5000);
// addFiles.click();
upload.sendKeys(exactPhoto);
var previewPic = element(by.css('.fileupload_section.fileupload_files'));
browser.wait(EC.visibilityOf(previewPic), 5000);
browser.wait(EC.visibilityOf(uploadBtn), 5000);
uploadBtn.click();
browser.wait(EC.visibilityOf(uploadFinished), 30000);
expect(uploadFinished.getText()).toBe('Upload Finished');

Clickable But Not Visible?

I am fairly new to Protractor E2E testing and was wondering if it was possible for an element to be clickable (ExpectedConditions.elementToBeClickable) but not necessarily visible (ExpectedConditions.visibilityOf).
For example, I have the following code:
var EC = protractor.ExpectedConditions;
var tryItButtonClickable = EC.elementToBeClickable(tryItButton);
var tryItButtonVisible = EC.visibilityOf(tryItButton);
return browser.wait(EC.and(tryItButtonClickable, tryItButtonVisible), getWaitTime())
.then(function() {
var protocol = url.parse(myarray[0].url).protocol;
if (protocol === null) {
throw new Error('expected ' + protocol + ' not to be null');
}
})
Before adding the tryItButtonVisible piece, I would receive a time out error from Protractor, presumably because my tryItButton was clickable but hadn't been loaded into the DOM.
Is this true, or am I being redundant?
Thanks
This is offical clickable function of protractor
elementToBeClickable(elementFinder: ElementFinder): Function {
return this.and(this.visibilityOf(elementFinder), () => {
return elementFinder.isEnabled().then(passBoolean, falseIfMissing);
})
as you see, it checks element visibility first so answer is NO
resource:https://github.com/angular/protractor/blob/master/lib/expectedConditions.ts line:188

setBusy not executing

I have setBusy exucuting elsewhere in my application, but why not here....
This is reading in my site details, so without the setbusy the page looks like it's doing nothing.
_onRouteMatched: function (oEvent) {
//initialise display
var view = this.getView();
view.setBusy(true);
view.byId("shopInput").setValue("");
view.byId("effectiveDateFrom").setValue("");
view.byId("shop24Hrs").setSelected(false);
view.byId("shopClosed").setSelected(false);
view.byId("createNext").setVisible(false);
view.byId("createSubmit").setVisible(false);
//view.byId("createSave").setVisible(false);
// initialise the store view model
var oModel = this.getModel("site");
this.getModel().read("/SiteSet", {
success: function (oData) {
var oSiteData = oModel.getData();
oSiteData.Sites = oData.results;
oModel.setData(oSiteData);
}.bind(this)
});
view.setBusy(false);
},
Any Ideas?
Actually your code sets busy but resets it right away. The read method is asynchronous. You have to reset busy inside the success callback function (it could be a good idea to reset it in an error callback too).
_onRouteMatched: function (oEvent) {
//initialise display
var view = this.getView();
view.setBusy(true);
view.byId("shopInput").setValue("");
view.byId("effectiveDateFrom").setValue("");
view.byId("shop24Hrs").setSelected(false);
view.byId("shopClosed").setSelected(false);
view.byId("createNext").setVisible(false);
view.byId("createSubmit").setVisible(false);
//view.byId("createSave").setVisible(false);
// initialise the store view model
var oModel = this.getModel("site");
this.getModel().read("/SiteSet", {
success: function (oData) {
var oSiteData = oModel.getData();
oSiteData.Sites = oData.results;
oModel.setData(oSiteData);
view.setBusy(false);
}.bind(this),
error: function(){
view.setBusy(false);
}
});
},
Generally when using setBusy() you should mind this points:
Per default the busy indicator is displayed 1000 milliseconds after setBusy(true). There is a setBusyIndicatorDelay() function to control that delay (can be set to 0).
The busy indicator is always created deferred (using setTimeout()). JavaScript is singlethreaded. So if your code after calling setBusy() blocks, the busy indicator will not be displayed until your code has finished and the control flow is returned to the event loop. So don't try this: setBusy(true); model.loadData("/data", false /*synchronous*/); setBusy(false);
You can create a busy dialog object and then use open and close function in the success call back and error call back respectively. Please have a look at the code:-
_onRouteMatched: function (oEvent) {
//initialise display
var busyDialog= new sap.m.BusyDialog;
view.byId("shopInput").setValue("");
view.byId("effectiveDateFrom").setValue("");
view.byId("shop24Hrs").setSelected(false);
view.byId("shopClosed").setSelected(false);
view.byId("createNext").setVisible(false);
view.byId("createSubmit").setVisible(false);
//view.byId("createSave").setVisible(false);
// initialise the store view model
var oModel = this.getModel("site");
busyDialog.open();
this.getModel().read("/SiteSet", {
success: function (oData) {
busyDialog.close();
var oSiteData = oModel.getData();
oSiteData.Sites = oData.results;
oModel.setData(oSiteData);
}.bind(this)
});
busyDialog.close();
},

Cannot read property 'download' of undefined $cordovaFileTransfer in Ionic

I want to use $cordovaFileTransfer in my app to dowload image data, but after trying to implement the code, this error is showing up:
Cannot read property 'download' of undefined
here is my code:
var url = "blablabla.com/img.png";
var targetPath = "img/"+ imgpaths;
var trustHosts = true;
var options = {};
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function(result) {
// Success!
console.log('Download Success' + targetPath);
}, function(err) {
// Error
}, function (progress) {
$timeout(function () {
var downloadProgress = (progress.loaded / progress.total) * 100;
console.log('Progress : '+downloadProgress);
});
});
anybody can help me?
Check this issues list:
http://ngcordova.com/docs/common-issues/
For example have you wrapped the call to $cordovaFileTransfer.download() inside deviceready handler or better inside $ionicPlatform.ready() ?

Chrome App FileReader

I'm trying to make use of the file system API in a Chrome App. I've tried all the sample code I can find and can't get a simple text file to read. I'm logging almost every step, and what seems to happen (or not happen) is everything stops the first time I reference a file reader object. It creates just fine, because I can log the .readyState, but after that I can't seem to even set an onload()event or execute a .readAsText().
Here's what I'm calling from a button:
function clickButton(){
chrome.fileSystem.chooseEntry({type: 'openFile', acceptsMultiple: false}, function(FileEntry){
if(chrome.runtime.lastError) {console.warn("Warning: " + chrome.runtime.lastError.message);}
else{
console.log(FileEntry);
var thing = new FileReader();
console.log(thing.readyState);
thing.onloadstart(function(){
console.log("Started loading " & FileEntry);
});
console.log("added onloadstart");
console.log(thing.readyState);
console.log(thing);
thing.readAsText(FileEntry);
console.log(thing.readyState);
console.log(thing.result);
}
});
document.getElementById("status").innerHTML = "I did something";
}
I did read somewhere that Chrome doesn't allow access to local files, but the chrome apps seem to be different. At least, the documentation seems to suggest that.
The only thing I end up with in my console is the FileEntry object.
https://developer.chrome.com/apps/app_storage#filesystem
I've used the example code right from the above link and still can't get it right. Anyone else have this issue or know what I'm doing wrong?
There is a difference between a FileEntry and a File. You need to call FileEntry's .file() method. So, replace
thing.readAsText(FileEntry);
with
FileEntry.file(function(File) {
thing.readAsText(File)
})
https://developer.mozilla.org/en-US/docs/Web/API/FileEntry#File
Try this code...
<!doctype html>
<html>
<script>
function handle_files(files) {
for (i = 0; i < files.length; i++) {
file = files[i]
console.log(file)
var reader = new FileReader()
ret = []
reader.onload = function(e) {
console.log(e.target.result)
}
reader.onerror = function(stuff) {
console.log("error", stuff)
console.log (stuff.getMessage())
}
reader.readAsText(file) //readAsdataURL
}
}
</script>
<body>
FileReader that works!
<input type="file" multiple onchange="handle_files(this.files)">
</body>
</html>
I've written a function to extract text from a file.
function getFileEntryText(fileEntry) {
return new Promise(function (resolve, reject) {
fileEntry.file(function (file) {
var fileReader = new FileReader();
fileReader.onload = function (text) {
resolve(fileReader.result);
};
fileReader.onerror = function () {
reject(fileReader.error);
};
fileReader.readAsText(file);
});
});
}
You can invoke this method like so:
getFileEntryText(fileEntry).then(function(text) {
// Process the file text here
}, function(error) {
// Handle the file error here
});
One thing I'm grappling with when working with the FileSystem is that every call is asynchronous. Having multiple levels of nested callbacks can make for code that's hard to read. I'm currently working around this by converting everything I can to a Promise.
for anyone who is interested, here's my final (working) code, complete with all the console.log()'s I needed to follow all those callbacks.
var chosenEntry = null;
function clickButton(){
console.log("Button clicked");
var accepts = [{
mimeTypes: ['text/*'],
extensions: ['js', 'css', 'txt', 'html', 'xml', 'tsv', 'csv', 'rtf']
}];
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: accepts}, function(theEntry) {
if (!theEntry) {
output.textContent = 'No file selected.';
return;
}
// use local storage to retain access to this file
chrome.storage.local.set({'chosenFile': chrome.fileSystem.retainEntry(theEntry)});
console.log("local data set. calling loadFileEntry");
loadFileEntry(theEntry);
console.log("loadFileEntry called, returned to clickButton()");
});
}
function loadFileEntry(_chosenEntry) {
console.log("entered loadFileEntry()");
chosenEntry = _chosenEntry;
chosenEntry.file(function(file) {
readAsText(chosenEntry, function(result) {
console.log("running callback in readAsText");
document.getElementById('text').innerHTML = result;
console.log("I just tried to update textarea.innerHTML");
});
});
console.log("added function to chosenEntry.file()");
}
function readAsText(fileEntry, callback) {
console.log("readAsText called");
fileEntry.file(function(file) {
var reader = new FileReader();
console.log("Created reader as FileReader");
reader.onload = function(e) {
console.log("called reader.onload function");
callback(e.target.result);
};
console.log("calling reader.readAsText");
reader.readAsText(file);
});
}