How to write wait condition for browser.title()? - angularjs

I'm looking for a wait condition to get the browser title. Currently, i use browser.getTitle() to get the browser title. Somehow, my script times out waiting to get the browser title. I can't use browser.sleep in this case. How do i achieve this by using browser.wait() condition?
Any help with be greatly appreciated. Thanks!

This seems like a perfect use case for the titleIs ExpectedCondition. Could you give it a try?
var EC = protractor.ExpectedConditions;
browser.wait(EC.titleIs('foo'), 5000, 'Title not "foo" after 5 seconds');

function waitForTitle(expectedTitle: string, time: number) {
return browser.wait(() => {
return browser.getTitle().then((currentTitle) => {
return currentTitle === expectedTitle;
});
}, time);
}
You just need to remember that time is given in ms.

Related

Wait for AngularJS Service to finish running (chrome console)

I'm manipulating some angular services/functions via Chrome console. (I have to specifically do this for a task I'm working on).
What I want to do is wait for the AddBagIfLimitNotReached() function to execute and finish running. And only then access the variable this.option.Quantity.
angular.element(document.querySelector(".quantity-button")).controller()._registeredControls[1].Scope.AddBagIfLimitNotReached = async function(n) {
console.log("tthis", this)
if (this.HasReachedMaximumBaggageAllowance()) {
angular.element(document.querySelector(".quantity-button")).controller()._registeredControls[1].LuggageDrawersService.OpenLuggageLimitReachedDrawer();
return;
}
this.AddBag(n);
console.log("Quantity", this.option.Quantity);
};
With this function, I'm adding a product to my basket. And this.option.Quantity should console.log 1. But it actually consoles.log 0.
However, if I check the object itself, it shows 1.
So I think what is happening, is I'm console.logging my bag quantity, before the bag has actually finished being added to the basket.
For example, if I added a settimeout of 2 seconds, the correct bag value = 1 is console.logged.
angular.element(document.querySelector(".quantity-button")).controller()._registeredControls[1].Scope.AddBagIfLimitNotReached = async function(n) {
console.log("tthis", this)
if (this.HasReachedMaximumBaggageAllowance()) {
angular.element(document.querySelector(".quantity-button")).controller()._registeredControls[1].LuggageDrawersService.OpenLuggageLimitReachedDrawer();
return;
}
this.AddBag(n);
// Returns 1
setTimeout(function(){ console.log("Quantity", this.option.Quantity); }, 2000);
};
Is there a better way I can achieve this, without using settimeout? I have tried async/await/promises, but I still can't seem to find a way to wait for the function to finish loading.
Async/await returns an error - it doesn't like the function this.HasReachedMaximumBaggageAllowance() and throws an error stating this.HasReachedMaximumBaggageAllowance is not a function.
Any tips/ideas would be much appreciated.
I found a solution, I'm using $watch, to watch a key/value, in the this object. And this seems to work:
angular.element(document.querySelector(".quantity-button.plus-button")).controller()._registeredControls[1].Scope.AddBagIfLimitNotReached = function(n) {
let bagCount = this.option.Quantity;
console.log("bagCount", bagCount);
if (this.HasReachedMaximumBaggageAllowance()) {
angular.element(document.querySelector(".quantity-button.plus-button")).controller()._registeredControls[1].LuggageDrawersService.OpenLuggageLimitReachedDrawer();
return;
};
this.AddBag(n);
this.$watch("this.option.Quantity", function (newValue) {
console.log(`Value of foo changed ${newValue}`);
if (newValue > 0) {
document.querySelector(`.luggage-tile-weight-${n.Weight} .tile-title .tick-box`).classList.add("green-tick");
displayGreenTickNoBagSelected();
};
if (newValue === 0) {
document.querySelector(`.luggage-tile-weight-${n.Weight} .tile-title .tick-box`).classList.remove("green-tick");
displayGreenTickNoBagSelected();
};
});
};

The array gets cleared after mongoose.findOne()

I am trying to get documents out of the database (questions) and store them in an array for further use (The questions would be asked to the players).
However, when I call findOne(), and add it's result to an array, the array is empty after the callback.. Even though it contains the data in there!
private Questions: iGeneralQuestion[];
private LoadQuestions(): iGeneralQuestion[] {
const result: iGeneralQuestion[] = [];
for (let qid of this.GeneralArguments.questionIds) {
QuestionModel.findOne({ id: qid }, (err: any, question: any) => {
if (err) return err;
if (!question) return question;
this.Questions.push({
questionId: question.id,
question: question.question,
answer: question.answer,
otherOptions: question.otherOptions,
timeLimit: question.timeLimit,
difficulty: question.difficulty
//explanation: question.explanation
//pictureId: question.pictureId
});
console.log(this.Questions); //The array is full here! (Gets filled with each iteration)
});
}
console.log(this.Questions); //But it doesn't contain anything here!
return result;
}
This is the code that loads the documents, and saves their content in the array.
I have tried using the promise functions and find() instead of findOne().. To no avail!
I'm absolutely lost with this, as it shouldn't be about some kind of scope error. The Questions array is a field variable, but it seems to get cleared in the end.
Any help is appreciated!
When you call QuestionModel.findOne({ id: qid }, (err: any, question: any) => {...});, you're registering a callback function that will be invoked after the document is found. But in the meantime (while findOne(...) looks for the document) the rest of the code continues to execute.
So after you've called QuestionModel.findOne(...), the for loop continues. You haven't found a document yet - that's happening in the background. Eventually the for loop will complete and the last console.log(this.Questions) on the page is called followed by return result;. But, findOne(...) is still looking for documents in the background. It hasn't found anything yet, so console.log(this.Questions) doesn't display anything. The array is still empty at this point in time. Awhile later, after findOne(...) finally finds a document, then the callback is called.
It may be worth looking into promises when dealing with asynchronous code like this:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
More optimize way(reduce DB operations) instead of finding each record, find all recode in one shot than creating the result. Hope this helps :)
private LoadQuestions(cb){
const result: iGeneralQuestion[] = [];
QuestionModel.find({
id: {
$in: this.GeneralArguments.questionIds // Array of all ids
}}, (err: any, questions: any) => {
if (err) cb(err);
questions.forEach((question) => {
if (question) {
result.push({
questionId: question.id,
question: question.question,
answer: question.answer,
otherOptions: question.otherOptions,
timeLimit: question.timeLimit,
difficulty: question.difficulty
//explanation: question.explanation
//pictureId: question.pictureId
});
}
});
return cb(null,result);
});
}

Pause protractor script while a class is present?

I'm trying make sure that the protractor test cannot continue while a class is present in my angular app. The class is responsible for locking the ui with a high z-index so the user wouldn't be able to click anything. I want to simulate this in my test. However, I'm not having any luck with this code:
// Wait http commands to finish
browser.wait(function() {
console.log(element(by.className('is-fetchingData')).isPresent());
return element(by.className('is-fetchingData')).isPresent()
}, 10000);
browser.wait(function() {
return element(by.className('is-fetchingData')).isPresent().
then(function(isPresent){
console.log("Is Element Present? - "+isPresent);
if(isPresent){
return true;
}
});
},'element is not present till timeout reached', 10000);
You can also do it using expected condtions, Look at below example
var ele = element(by.className('is-fetchingData'));
var EC = protractor.ExpectedConditions;
// Waits for the element to be no longer visible on the dom.
browser.wait(EC.invisibilityOf(ele), 5000); //this will wait untill the element is disappeared from the page.

How to wait for rows to load with Protractor

I'm trying to use protractor to select a row, count rows, etc. This doesn't seem to be working:
var GridTestUtils = require('./gridObjectTestUtils.spec.js');
var GridTestObj = new GridTestUtils('exampleGrid');
var Grid = GridTestObj.getGrid();
browser.wait(function(){
return Grid.isPresent();
}, 1000).then(function(){
GridTestObj.expectRowCount( 25 );
});
It seems as though it's trying to find the rows before they're loaded. The test keeps failing with 'Expected 0 to equal 25'.
I can get it to work if I use browser.sleep but there has to be a better solution than that.
How do I tell protractor to wait for Angular ui-grid to load completely?
I would do that with browser.wait() and a custom Expected Condition:
var rows = Grid.element( by.css('.ui-grid-render-container-body')).all( by.repeater('(rowRenderIndex, row) in rowContainer.renderedRows track by $index') );
browser.wait(function () {
return rows.count().then(function (countValue) {
return countValue > 0;
});
}, 5000);
In this case, protractor would execute the function passed into browser.wait() continuously until it evaluates to true or the timeout happens (in 5 seconds).

tell Protractor to wait for the page before executing expect

When I click the export button, it makes a REST call to our endpoint then few seconds after, I receive the response then I also render the table. Unfortunately, I read that every call is asynchronous which means my expect will be executed even if table hasn't been rendered yet. The expect I wrote checks if the string is on the table but it's failing since it's not there yet. What is the proper approach to this?
it('should generate global user report', function() {
element(by.css('button#exportButton')).click();
expect(element(by.css("th[name*=Date]")).getText()).
toEqual('Date');
})
The error on the console is
NoSuchElementError: No element found using locator: By.cssSelector("th[name*=Date]")
I noticed that the table hasn't been rendered yet that's why it's failing.
Protractor 1.7 introduced a feature called "Expected Conditions", that can be applied here.
Wait for element to become visible:
var EC = protractor.ExpectedConditions;
var elm = element(by.css("th[name*=Date]"));
browser.wait(EC.visibilityOf(elm), 5000);
expect(elm.getText()).toEqual('Date');
I had problem waiting for a dynamic element to appear. Have the driver wait for it to either be present or displayed. The number at the end is the timeout.
element(by.css('button#exportButton')).click();
var header = element(by.css("th[name*=Date]"));
browser.driver.wait(function() {
return header.isPresent();
}, 1000);
expect(header.getText()).toEqual('Date');
I had to wait until it was present AND displayed before the test was fully stable. You can do that like this:
var header = element(by.css("th[name*=Date]"));
browser.driver.wait(function() {
return header.isPresent().then(function(present) {
if (present) {
return header.isDisplayed().then(function(visible) {
return visible;
});
} else {
return false;
}
});
}, 1000);

Resources