How to write wait until without installing plugin for it.
For example wait until loading spinner element is replaced with plain text in button element.
I tried with different combinations of should like:
cy.get("somekey",{timeout:60000}).should("have.text","exampletext").click({force:true});
I am not getting consistant execution. Could replacing element with plain text play role?
Related
I am writing a very simple SPA application that has a single read-only 'output' field, followed by a single input field. When the user types an input command and hits enter, the JavaScript writes text into the output field. I want the screen reader to read this output straight away without the user having to navigate to the output field, so I added aria-live, thus:
<div>
<div class="output" aria-live="polite">{{myViewModel.output}}</div>
<input type="text" myAngularDirective />
</div>
In the first iteration this worked exactly as I wanted. However, some of the commands change the Url (though rendered using the same view) and I wanted to ensure that the focus is left on the input field, and in most cases, the input field is cleared for the next command. When I add code either to focus on the input, or modify it, the output still renders fine on the screen but is no longer read out by the screen reader.
I've tried:
Changing (in the JavaScript) the order of writing the output and
clearing/focussing on the input
Upping the aria-live to 'assertive'
Adding aria-live to the input also (not sure why I thought that would
help)
Moving the aria-live from the output field to the surrounding div
None has made a difference. If I remove the focus/clear logic, all works well again. There is some subtlety about how aria-live works that I am missing: any help appreciated.
It's difficult to answer your question without a reproducible code sample, and you haven't mentioned which browser and screen reader combination you were testing with. But, it may be that with your focus logic is overriding the aria-live="polite" setting. For example, when the page is updated, the aria-live announcement is queued (because aria-live="polite" is the least intrusive setting), but when the keyboard focus is then intercepted to keep focus in the `, this overrides the announcement.
I am writing a CKEDITOR plugin that needs to wrap certain pieces of text in a tag. From a webservice, I have an array of items that need to be wrapped. The array is just the plain text strings. Such as:
"[best buy", "horrible migraine", "eat cake"]
I need to find the instances of this text in the editor and wrap them in a span tag.
This is further complicated because the text may be marked up. So the HTML for "best buy" might be
"<strong>best</strong> buy"
but the text returned from the web service is stripped of any markup.
I started trying to use a CKEDITOR.htmlParser() object, and that seems like it is moderately successful. I am able to catch the parser.onText event and check if the text contains anything in my array.
But then I cannot modify that text. Modifications are not persisted back to the source html. So I think using the htmlParser() is a dead-end.
What is the best way to accomplish this task?
Oh, and as a bonus, I also do not want to lose my user's current cursor position when the changes are displayed.
Here is what I wound up doing and it seems to be working so far.
I created a text filter rule that searches through my array of items for any item that is contained (or partially contained) in the text. If so, it wraps the element in my span.
A drawback here is that I wind up with two spans for items with markup. But in my usecase, this is tolerable.
Then I set the results using:
editor.document.getBody().setHtml(results);
Because of this, I also have to strip this markup back out when this text gets read. I do this using an elements filter on editor.dataProcessor.htmlFilter.
This seems to be working well for my (so far limited) test cases.
I have the following HTML:
<input type="button" value="Close List" class="tiny round success button" id="btnSaveCloseListPanel">
The following code does not work:
# browser.button(:value => "Close List").click # does not work - timeout
browser.button(:xpath => "/html/body/center/div/div[9]/div[2]/input[2]").when_present.click
The error is:
Watir::Wait::TimeoutError:
timed out after 60 seconds
when_present(300) does not work.
I found the XPath using Firefox Developer Tools. I used the complete path to avoid any silly errors. I can find the same path manually in IE.
The component is a .NET MVC popup. I think it's called a "panel". The panel is a grandchild of the Internet Explorer tab.
The panel contains a datepicker, a dropdown, a text box, and 3 buttons. I can't find any of these using Watir. I can find anything in the panel's parent (obviously).
The underlying code does not seem to be aware that something actually doesn't exist. To prove that, I tested the following XPath, which is simply the above XPath with the middle bit removed:
browser.button(:xpath => "/html/body/center/div/input[2]").when_present.click
The error is "timeout", rather than "doesn't exist".
So, the code seems to be unaware that:
input[1] does not exist, therefore input[2] cannot exist.
div[2] does not exist.
Therefore there's nothing left to search.
Added:
I'm changing the specific element that I want to find.
Reason: The button in my OP was at the foot of the panel. I was going cross-eyed trying to step upwards through hundreds of lines of HTML. Instead, I'm now using the first field in the panel. All the previous info is still the same.
The first field is a text field with datepicker.
The HTML is:
<input type="text" value="" style="width:82px!important;" readonly="readonly" name="ListDateClosed" id="ListDateClosed" class="hasDatepicker">
Using F12 in Firefox, the XPath is:
/html/body/center/div/div[1]/div[2]/input
But, now, with a lot less lines of HTML, I can clearly see that the html tag is not the topmost html tag in the file. The parent of html is iframe
I've never used iframe before. Maybe this is what t0mppa was referring to in his comment to the first questiion.
As an experiment, I modified my XPath to:
browser.text_field(:xpath, '//iframe/html/body/center/div/div[1]/div[2]/input').when_present.set("01-Aug-2014")
But this times out, even with a 3-minute timeout.
Given that the elements are in an iframe, there are two things to note:
Unlike other elements types, you must always tell Watir when an element is in an iframe.
XPaths (in the context of Watir) cannot be used to cross into frames.
Assuming that there is only 1 iframe on the page, you can explicitly tell Watir to search the first iframe by using the iframe method:
browser.iframe.text_field(:xpath, '//body/center/div/div[1]/div[2]/input').when_present.set("01-Aug-2014")
If there are multiple iframes, you can use the usual locators to be more specific about which iframe. For example, if the iframe had an id:
browser.iframe(id: 'iframe_id')
.text_field(xpath: '//body/center/div/div[1]/div[2]/input')
.when_present
.set("01-Aug-2014")
My application under test has been developed by external suppliers so I have no control over the HTML structure. The application is extremely Javascript and Ajax heavy, with numerous dynamically generated buttons and auto-complete lists.
In other words, the characteristics of the pages are that they are filled with:
Elements with no fixed IDs (IDs are generated on the fly and have
numbers or other text dynamically added to them)
The same happens with some classes
Most of the times the buttons have no text associated with them since they are either custom coded 'down' arrows for lookup lists
(which aren't lookup lists but hidden divs) or '+' and '-' icons to
maximise or minimise portions of the content. -
It is therefore very difficult to identify these elements, especially the buttons.
I am trying to write a generic 'I click on the button near y' type of step so that it is not necessary to hardcode each and every button (assuming I can even get something to identify them with) into each and every test.
The thinking behind this is that normally there is a label of some sort close to the button at least.
What I want to to is to find the text label, then see if there is a button inside the same scope, and if there is not, move 'back' through the parent elements, and check if there is a button inside the scope of each parent level, up to 5 parents.
There might be all sorts of problems with this approach but I am just curious to see if this will work in general. I have run into some problems.
First I tried to use Xpaths, so I got the Xpath of the parent through :
$parentelement = $element->getParent();
$parentXpath->getXpath();
This would give me an Xpath of : (//html//span[text()='Cost center'])[1] and moving up through the parent elements all the time, they would become successively:
(//html//span[text()='Cost center'])[1]/..[1]
(//html//span[text()='Cost center'])[1]/..[1]/..[1]
and so forth.
The actual button is located in: (//html//span[text()='Cost center'])[1]/..[1]/..[1]//button but it has to go through all the parent elements in order to get there, so it will start with (//html//span[text()='Cost center'])[1]//button and should end with (//html//span[text()='Cost center'])[1]/..[1]/..[1]//button where it should find the button.
Trying to use Xpath I used:
$button_element = $session->getPage()->find('xpath',$parentXpath."//button")
I soon saw that the 'find' command appends an //html to the front of your xpath string so the Xpath that it tried to use ended up being (for each parent Xpath, but using this one as an example):
(//html(//html//span[text()='Cost center'])[1]/..[1])
I then stripped out the brackets as well as the //html, leaving me with:
//span[text()='Cost center'][1]/..[1]
but when I tried:
$button_element = $session->getPage()->find('xpath',$strippedParentXpath."//button")
I got the following error:
SyntaxError: Failed to execute 'evaluate' on 'Document': The string '(//html//span[text()='Cost center'][1]/..[1]//button)[1]' is not a valid XPath expression
However, Firepath can execute this expression and does not show a syntax error for it, although it does not find the actual button (since the button is actually located one level up, where Firepath DOES find it).
So my question 1 is: What is wrong with my Xpath that I can't use it in the find? It actually looks as if //span[text()='Cost center'][1]//button does not throw the same exception, since as I said, I am looping through the parent Xpaths, and it starts with //span[text()='Cost center'][1]//button. It crashes on //span[text()='Cost center'][1]/..[1]//button.
My second option was to get the parent element each time, starting with finding the text on the page, but then to search for a button inside the scope of the parent element using the findbutton functionality.
Looping through the parent elements (up to a maximum of 5):
$parentelement = $parentelement->getParent();
$butonelement = $parentelement->findbutton('xxx');
In other words, find ANY button in the scope of the parent element. The problem I have is how to specify a generic 'button'.
One has to associate SOME text with the button (depicted by the 'xxx' above).
But this is a typical example of buttons in the application:
<button class="autocomplete_button" type="button" id="button_OM_1"> </button>
Where the class is used more than once, and the ID is auto-generated and not the same number all the time. There is no text associated with the button since the class specifies an image.
Question 2: So how can I use 'findbutton' to generically find a 'button' no specific distinguishing characteristics? Please note that I actually did try findbutton("button"), taking the chance that there might be a 'button' somewhere in a button, but this did not work either. At least, it doesn't work consistently and by that I mean that the same test randomly seems to either find or not find the same button when I run the test a couple of times.
After doing some more investigation on this issue I have found the following:
My method of trying to find the closest button to a piece of text via traversing 'up' through the scope of the divs and spans around the text (using xpath) is actually working.
What is NOT working is SAHI, which I am using as the web driver. In other words, it is not a Behat/Mink problem, it is SAHI specific issue.
I tried the same code using Selenium2 and it executes perfectly.
I still require an answer to question 2 - how can I use findbutton() without a specific parameter such as the ID, name or value but I will see if I can find an answer to that question separately and on the Behat user group since I do think that is a Behat/Mink specific issue.
I normaly use css selector and with that, I use to navigate to the class and ID's that the button is inside. it is easier than xpath I think, like you can use
$this->getSession ()->getPage ()->find ( 'css', '.parrent1 .parrent2 .autocomplete_button ' );
I think this will help you as you know which button your gonna use in each scenario
Sorry if this question was mentioned. I have web page with bunch of javascript files. One of it has function that sets value to some input on HTML file. Is it possible to see via debugger which javascript function invokes changing of value of the input HTML element?
Right click on the input tag that you are willing to observe and select Break On and then Attribute Modifications. Your scripts will stop if they try to modify the input value.