In what circumstances would I need to use Protractor ExpectedConditions to wait for an element - protractor

I'm new to working with Protractor and I was wondering in what circumstances would you need to use ExpectedConditions (example below) when using Protractor. I thought that Protractor automatically determine when an AngularJS page is fully loaded.
let EC = ExpectedConditions;
let condition = EC.presenceOf(element(by.id("something")));
browser.wait(condition, 10000);
Thanks, Eric

From my experience working with Protractor, the use of ExpectedConditions depends on the behavior of the page you are automating. It's mostly used due to failing if the condition doesn't comply in the specified time.
These conditions will also return a promise that you can handle to your liking.
I'll give you a few scenarios so you can understand where to use them.
alertIsPresent(): This condition will wait till an alert appears.
e.g.: After clicking a button, there will be an alert appearance; however, there's an API call which makes the pop-up take longer and also a small animation, so we want to wait a few seconds and no more than that.
// will click on a button
element(by.id('button')).click();
// will wait for the condition
let EC = ExpectedConditions;
browser.wait(EC.alertIsPresent(), 5000);
The following code will wait for 5 seconds after clicking the button, to see if the alert is present, else it will throw an error.
invisibilityOf(): This condition will wait till the specified element is not being displayed.
e.g.: There's a loader that appears for every single action that is triggered in the page. For this we want to wait till this loader disappears so we can continue with the automation process. By business requirements, this loader shouldn't take longer than 10 seconds.
This loader locks the whole page, so other elements are not interactable while it is up.
// trigger random action on page so loader appears
element(by.id('button2')).click();
// will wait for the condition
let EC = ExpectedConditions;
browser.wait(EC.invisibilityOf(element(by.id('loader'))), 10000);
After clicking a button, we will give a 10 seconds grace for the loader to disappear, else the condition will throw an error.
elementToBeClickable(): This condition will wait till the specified element can be clicked.
e.g.: The button to the login form is disabled by default, so it can't be clicked unless we complete the username and password textfields. The button being enabled after filling the textfields has a fast animation, either way we want to give it 1 second to complete and check if we are able to click it.
// complete both textfields required for the button to be enabled
element(by.id('username')).sendKeys('User1234');
element(by.id('password')).sendKeys('Protractor');
// will wait for the condition and then will click the button
let EC = ExpectedConditions;
browser.wait(EC.elementToBeClickable(element(by.id('loginButton'))), 1000);
element(by.id('loginButton')).click();
After completing both textfields, the condition will wait for 1 second for the element to be clickable, if it is, it will procede with the next line and click it. On the other hand, if it doesn't, an error will be thrown.
presenceOf(): In this case, the condition will check if the element is present in the DOM (Document Object Model) but it won't check if the element is visible or not.
e.g.: On a page with a radio button group containing 3 flavors: chocolate, vanilla and strawberry. Depending on which you choose, you will be shown different questions. Developers mentioned that the questions are in the page at all moments, but are hidden due to which radio button is selected at the moment. In this situation, we just want to check that all questions exist in the DOM, whether or not they will be shown by a radio button being selected.
// check all questions directly, without selecting any radio buttons
let EC = ExpectedConditions;
browser.wait(EC.presenceOf(element(by.id('question-1'))), 1000);
browser.wait(EC.presenceOf(element(by.id('question-2'))), 1000);
browser.wait(EC.presenceOf(element(by.id('question-3'))), 1000);
The time is pretty irrelevant here; nonetheless, using this conditions we will be able to check that the questions, even though hidden, exist in the DOM. If one is missing, an error will cut the test immediately.
These were a few examples I've had to deal with in the past. The use of the conditions is situational and mostly they are useful when you want to use the existing conditions since they save you the time of building them yourself.
PD: More information can be found in the Protractor API.

Related

How to know closing event of sub form in parent form

I have a main form with :
a table of data (list of pay)
a button calling a subform (assistant form to create easily a bound of pay for a complete year)
After closing the subform, I have to update the main form data (table view) only if the user click Generate (to avoid data update), ie only if the user generate new payroll.
Is there a way to know if the user cancel or not action in the subform?
Ok, so you NOT really talking about a form + sub form.
There are two ways to do this:
First, you can open the 2nd child form as acDialog (not modal - very big difference).
So, your main form code can do this:
Dim strF As String
strF = "frmChildForm"
DoCmd.OpenForm strF, , , , , acDialog
' CODE WILL HALT and wait for above form to be closed
' code here continues
' can even update data on this main form from that child form.
If CurrentProject.AllForms(strF).IsLoaded Then
' user hit ok - or your save button
Me.LastChildUpdate = Forms(strF)!LastUpdate
DoCmd.Close acForm, strF
Else
' code goes here - user hit cancel button, or X to close - we assume cancel
End If
Now in that other child form, you DO NOT CLOSE when your "done/save/ok" button runs. It simply sets the form's visible property to false
eg:
Me.Visible = False
So, now our calling code will WAIT until the user is done. If the form is closed, then we assume a user "canceled" that child form.
so, the user can hit X to close, OR the user might hit your close/cancel button. Your close/cancel button thus can close the form. eg this code:
docmd.Close acForm,me.name
So, now you know if the user canceled (closed) the form. Your "ok/save" button in that form ONLY sets the forms visible=False. That makes the calling code continue, and then you check if the form is open or not - and thus your code can take appropriate action.
However, you don't even have to use the "halt" code trick above.
What you can do in that child form you launch?
You can in the on-open event, or even on-load? You pick up the name of the calling form.
So, you define this in your code:
Option Compare Database
Option Explicit
Dim frmPrevious As Form
Private Sub Form_Load()
Set frmPrevious = Screen.ActiveForm
End Sub
So, now your save button on this form?
It can call/use/update ANYTHING from the main previous form caller.
So, your save button can now;
frmPrevious.Refresh
Or
frmPrevous!LastName = me.LastName
So, you can do "anything" by replacing "me" with frmPrevous, and any operation (such as your custom save button on that 2nd form) can update, call code, refresh, or do anything it wants to operation on the first main calling form.
And you can even call subs/functions in that main form.
So, you could have a public sub in the main form, and in the 2nd form, on the close event do this:
Call frmPrevous.MySubName ' tell + call code in main form.
docmd.close acForm,me.name
So the above outlines two approaches:
First idea:
You open 2nd form as "acdialog" and the code waits. You either then close the 2nd form (considered a cancel), or you save visible=false and the calling code CONTINUES.
Second idea:
You pick up the previous form in the on-load event. Now your save button can directly update values, controls etc. in "frmPrevious", and then once done, you close the 2nd form in that "ok button" routine.
So, quite much is that in that 2nd form, you can directly update controls and do things to the first calling form with the above 2nd idea.
Or, as noted, you can HALT the calling code that opens the form, wait for user response, and then use the visible=false trick to allow the calling code to continue. Once again, since the 2nd form is still open, you are free to get/grab/take values from that STILL open form, and then when done you thus as a last stop close that 2nd form. So in effect, your 2nd form does NOT close when the user is done - but only visible = false. As noted, this trick only works if you open/call the 2nd form as "acDialog". This is a great idea for say yes/no dialog prompts etc., since then you can upon user selection have the calling code continue, and examine the values in that 2nd form before closing it.
And the last but not least method:
In that 2nd form the code behind your "ok" button can simple update the first form
forms!MyFirstForm!LastName = me.LastName
docmd.close acForm,me.name
However, above has the form(s) name hard coded, and frmPrevious trick is thus somewhat better since then you don't hard code the calling forms name, and thus many forms can call + use that same 2nd form.

How to wait for element or wait for element to be clickable in protractor?

How to use wait for element to be clickable and wait for element to be present in protractor? I know this will help only with 1 element. Not for all.
For Example:-
Here is the website link, I am trying to automate using protractor and I do not want to use sleep in any case.
Steps to reproduce:-
Navigate to https://www.celebritycruises.com.
Click on Find A Cruise at top left corner and click on Find Cruise button.
It will be navigated to this link - celebritycruises.com/spa/#/itinerary-search.
Now here is the thing, This page takes time to load. So, I am trying to wait for the element or wait for element to be clickable. But it is getting failed.
browser.get('https://www.celebritycruises.com');
var pop = element(by.css('a.popover-find-cruise'));
pop.click().then(function() {
element.all(by.css('.cta.find-cruise-button button')).last().click();
});
var dta = element(by.css('.itinerary-search.spa #nav-departure-date'));
var EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(dta), 30000);
dta.click();
Can you please help me on this?

Code to click a radio button does not work the second time in my Protractor script

I am calling a function twice to execute a piece of code in my protractor script. A snapshot of the code of my function that is failing when called the second time is below. sessionNo is an argument passed to this function. It could be either 0 or 1. Depending on the value of this argument, either the radio button with index 0 will be selected or the radio button with index 1 will be selected.
function sessionBegin(sessionNo)
{
element.all(by.repeater('type in types')).all(by.css ("input[type='radio']")).isPresent(). then(function()
{
var sessionType = element.all(by.repeater('type in types')).all(by.css ("input[type='radio']")).get(sessionNo);
sessionType.click();
});
}
This code works great when this function is called for the first time. But when it is called the second time with a different value for sessionNo, it fails with "Failed: element not visible" error. I can't figure out why is the above code unable to locate the same element for the second time as it did for the first time with the exact same code.
It depends on your application code, may be your element becomes invisible between it's found and click action, or it's not visible yet. For the first case you should investigate what happens in application side, for second case (if it's not visible yet), you can wait until it became visible, for example: browser.wait(EC.visibilityOf(element), 5000, Element not visible: ${element.locator()});
it will wait for for element 5 seconds.

Unity/NGUI Updating List at runtime

I was wondering if someone could explain to me how I update a list at runtime in Unity?
For example I have a spell book, which has 3 spells in it, when I drag them to my action bar they get re-parented to it, what I'm trying to do is get a list of each child under the actionbar transform,
My problem is where to actually do something like this if I try something like below in the update, it adds whatever's there many times, which I can understand since update runs every frame..
list = actionbarui.GetComponent(UIGrid).GetChildList();
for(var i =0;i < list.size; i++)
{
buttonList.Add(list[i].gameObject);
}
If I add a callback to the buttons so that whenever they're drag and dropped it runs the above code and add thing's additively, as in, if you drag just one "spell" on it will loop through once, which is fine, but as soon as you add another it loops through three times, that is, it already has one it then adds the same one again PLUS the new button that's just been dragged on for a total of 3.
I've tried changing the code to
list = actionbarui.GetComponent(UIGrid).GetChildList();
for each(var child : Transform in list.GetEnumerator())
{
buttonList.Add(child.gameObject);
}
But this simple doesn't add anything, I am unsure how to go about keep the lists update as they are dragged off and on, could anyone please explain how this is achieved?
Please ignore the second "list" code, it's implementing "BetterLists" as apart of NGUI, so doesn't follow standard list methods.
Thank you for reading
If I add a callback to the buttons so that whenever they're drag and dropped it runs the above code and add thing's additively, as in, if you drag just one "spell" on it will loop through once, which is fine, but as soon as you add another it loops through three times, that is, it already has one it then adds the same one again PLUS the new button that's just been dragged on for a total of 3.
That is the expected result here. You are running through the list of children and adding them to your buttonlist, so first time there is only one item to add, then when you add another child there are two items to add, thus resulting in three items.
Either don't have a for loop and do:
buttonList.Add(the_GameObject_that_was_just_added_to_the_bar);
Or clear your buttonList before the for loop:
list = actionbarui.GetComponent(UIGrid).GetChildList();
buttonList.Clear();
for(var i =0;i < list.size; i++)
{
buttonList.Add(list[i].gameObject);
}
Alternatively to Dover8's response, you can first check if the buttonList already contains a reference to the child to be added. If it does, continue. Otherwise add the new child.
However, given the expense of doing the checks, and since you are already looping through the list already, I'd recommend that you follow his suggestion to clear the list before running the loop. It will probably give you the best performance out of these examples.
If there's a reason you can't or shouldn't clear the buttonList, and you still need to run through it, I'd recommend my suggestion. It really depends on which implementation works best for what you are trying to do. The point is that there are several ways to do this, and they have different performance profiles you need to consider.

QCompleter and Tab key

I'm trying to make a Completion when pressing tab, you get the first completion of all possibilities.
But, in a QWidget-based main window, pressing tab will make that QLineEdit lost focus, and completion popup hides after that.
Is there a way to fix it ?
Have you tried to subclass QLineEdit and intercept the key press event?
Alternatively you could set up an event filter.
Whew. It took me some time to figure this out :) Multiple times I have tried to solve this problem, but always gave up. Now, I dug enough to find the answer.
OP, please pardon me, because the code here is Python, but should be understandable and work for C++ as well.
Basically, the problem I had was "how to select an entry in the QCompleter"; I didn't notice before, but the answer is in the popup() method. QCompleter works with a model and a view, which contains the things to show.
You can change the current row as you wish, then get the index of that row in the model, then select it in the pop-up.
In my code, I subclassed QLineEdit, created a tabPressed signal which is emitted every time Tab is pressed. Then, connected this signal to a method of the same class which does this:
get the current index;
select the index in the popup;
advance to the next row.
As implementation, this is very trivial, but for my current purpose this is enough. Here's the skeleton (just for the tab part, it's missing the model and everything else).
class MyLineEdit(QLineEdit):
tabPressed = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self._compl = QCompleter()
self.tabPressed.connect(self.next_completion)
def next_completion(self):
index = self._compl.currentIndex()
self._compl.popup().setCurrentIndex(index)
start = self._compl.currentRow()
if not self._compl.setCurrentRow(start + 1):
self._compl.setCurrentRow(0)
def event(self, event):
if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab:
self.tabPressed.emit()
return True
return super().event(event)
You may need to adjust/fix few things, but this is the basic idea.
EDIT:
For details see
http://www.qtcentre.org/threads/23518-How-to-change-completion-rule-of-QCompleter
There's a little issue: when Return is pressed, the things don't work properly. Maybe you can find a solution to this problem in the link above, or in the referenced resources therein. I'll fix this in the next few days and update this answer.
There is probably a better solution but one that comes to mind is to change the focus policy for all other widgets on the form to something that doesn't include "tab" focus. The only options that don't use the tab key are Qt::ClickFocus and Qt::NoFocus.