Robot Framework: wait for an element to (dis)appear based on a custom HTML property? - html

I have a div with a property panelname that changes depending on which view in a multi step process I am in (every panel has a Next-button).
It takes a few seconds after each click on Next for the next panel to load and render. This div has the same ID on every step instead panelname changes for each view.
I can read the value for panelname using Get Element Attribute but how do I use this in one of the Wait until page/for element, or similar, keywords?

The following should work, assuming you know each panel's name:
Wait Until Page Contains Element //div[#id='sameId' and #panelname='name2']
This the example HTML for the keyword above:
<div id="sameId" panelname="name2"></div>

Related

Reloading a div removes it and does not show anything

When I try this line of code:
$("#topleft").load(location.href + " #topleft");
it removes the topleft div instead of reloading it.
I am executing the code above in a typescript file (specification.ts) but the HTML that contains topleft (view.html) is connected to a different typescript file (view.ts). Is this the reason why my div does not get reloaded?
Since the div you are trying to reload is in a different location, you will need to use the location that you are trying to reload from (in this case view.html) so the load function will look like this
$("#topleft").load("view.html #topleft");
location.href refers to the page executing the script, so this effectively will do nothing (since reloading the div from the same page will result in the same content).

headless chrome + rspec not able to select option form select list it gives error capybara element not found

I am using headless chrome, rspec - 3.6.0, capybara - 2.15.1
select('apple',from: 'fruits', visible: false)
page.find('#apple', visible: false).click
within 'results' do
page.find('.option', text: 'apple').click
end
Error:
Capybara::ElementNotFound: Unable to find visible css "#fruits .chosen-drop .chosen-results"
The error shown in your question is not from any of the other lines of code you show, however based on the error message it's pretty clear what's going on.
Attempting to perform any action on an element you've found using visible: false makes no sense because the user can't interact with a non-visible element (99% of time if you specify visible: false you're doing something wrong). In the current case you are using the chosen library which hides the normal HTML <select> element and replaces it with a JS driven widget made up of <ul> and <li> elements. Because of this you can't use the normal select method and instead need to interact with the page just like a normal user would (click on the 'chosen' field and then click on the element from the list). You haven't provided the actual HTML generated for your page, but based on your attempts and the output generated by the chosen demo page - https://harvesthq.github.io/chosen/ - it will be something like
<select id="fruits" ... style="display: none;>
...
</select>
<div class="chosen-container" ... >
...
<div class="chosen-drop">
...
<ul class="chosen-results">
<li ...>Apple</li>
<li ...>Orange</li>
...
</ul>
</div>
</div>
So to work with that the user would first need to click on the .chosen-conatiner element (sibling of the hidden select) to open the .chosen-drop element and then click on the correct <li> from the .chosen-results element which translates into something like
chosen_container = find('select#fruits + .chosen-container').click
chosen_container.find('.chosen-results li', exact_text: 'Apple').click
If that doesn't work for you then you'll need to add the exact HTML from your live page to your question.
Note: if you're dealing with a lot of chosen widgets in your site you may want to look into writing custom Capybara selectors -https://www.rubydoc.info/github/teamcapybara/capybara/Capybara#add_selector-class_method - to make the tests read a lot better

Dynamically adding onscroll function

I have a set of tabbed tables. tabs are added during runtime, and each tab has 4 tables with data associated with the tab.
I also have a requirement that each table scrolls data but the header remains visible and consistent with the scroll.
I have seen examples of this and implemented it just fine, well for the first tab.
Since the ids need to be unique, I use the Angular Js ng-attr-id to generate unique ids.
My problem now is how to reference the unique ids when creating the onscroll function.
With a single tab, I can use this code:
<table id="Orders" onscroll="$('#Orders > *').width($('#Orders').width() + $('#Orders').scrollLeft());">
This works absolutely fantastic, now using Angular's ng-attr-d, I don't know how to set the function since it needs to be dynamically created using the dynamic id:
<table ng-attr-id="Orders{{GroupDetails.length}}" onscroll="$('#Orders{{GroupDetails.length}} > *').width($('#Orders{{GroupDetails.length}}').width() + $('#Orders{{GroupDetails.length}}').scrollLeft());">
This above does not work. Inspection shows that the {{}} parts are rendered as string.
Is there an Angular JS way to 'inject' event functions?
Issue with syntax, you can add a variable to string and assign it to ng-attr-id.
Try this:
<div ng-attr-id="{{ 'orders-' + GroupDetails.length }}"></div>

How can I pass a value when creating a new tab panel with CSJS

I want to create a new tabbed panel for the Dojo tab container using CSJS like:
dijit.byId('#{id:djTabContainer1}').createTab({ tabTitle: Math.random()});
The default tab panel has an panel that will use the iframe tag and I want to pass in the above call the src html attribute to the panel.
Question : I can specify a url to load in the iframe. Is there a way to pass this?
It seems like the createTab only does certain tab related parameters like action and tabTitle.
Howard
The syntax is somewhat obscure here. Starting with the code in the ExtLib demo app:
XPagesExt.nsf/Core_DynamicTabs.xsp
Change the script in button4 to:
dijit.byId('#{id:djTabContainer1}')
.createTab({
"newName":'Tab'+Math.random(),
"newHref":'/XPagesExt.nsf/page5.xsp'})
to match the syntax you're requesting.
And, in the tab that's referenced by defaultTabContent, change the title and href to use those passed URL parameters:
<xe:djTabPane xp:key="doc" id="djTabPane2"
title="${javascript:/*load-time-compute*/param.newName}"
href="${javascript:/*load-time-compute*/param.newHref}"
It will create the tab and will attempt to load the href contents. I'm not seeing it as an iframe though - it's just a container div.

shrink html help

I have an array of 2000 items, that I need to display in html - each of the items is placed into a div. Now each of the items can have 6 links to click on for further action. Here is how a single item currently looks:
<div class='b'>
<div class='r'>
<span id='l1' onclick='doSomething(itemId, linkId);'>1</span>
<span id='l2' onclick='doSomething(itemId, linkId);'>2</span>
<span id='l3' onclick='doSomething(itemId, linkId);'>3</span>
<span id='l4' onclick='doSomething(itemId, linkId);'>4</span>
<span id='l5' onclick='doSomething(itemId, linkId);'>5</span>
<span id='l6' onclick='doSomething(itemId, linkId);'>6</span>
</div>
<div class='c'>
some item text
</div>
</div>
Now the problem is with the performance. I am using innerHTML to set the items into a master div on the page. The more html my "single item" contains the longer the DOM takes to add it. I am now trying to reduce the HTML to make it small as possible. Is there a way to render the span's differently without me having to use a single span for each of them? Maybe using jQuery?
First thing you should be doing is attaching the onclick event to the DIV via jQuery or some other framework and let it bubble down so that you can use doSomething to cover all cases and depending on which element you clicked on, you could extract the item ID and link ID. Also do the spans really need IDs? I don't know based on your sample code. Also, maybe instead of loading the link and item IDs on page load, get them via AJAX on a as you need them basis.
My two cents while eating salad for lunch,
nickyt
Update off the top of my head for vikasde . Syntax of this might not be entirely correct. I'm on lunch break.
$(".b").bind( // the class of your div, use an ID , e.g. #someID if you have more than one element with class b
"click",
function(e) { // e is the event object
// do something with $(e.target), like check if it's one of your links and then do something with it.
}
);
If you set the InnerHtml property of a node, the DOM has to interpret your HTML text and convert it into nodes. Essentially, you're running a language interpreter here. More text, more processing time. I suspect (but am not sure) that it would be faster to create actual DOM element nodes, with all requisite nesting of contents, and hook those to the containing node. Your "InnerHTML" solution is doing the same thing under the covers but also the additional work of making sense of your text.
I also second the suggestion of someone else who said it might be more economical to build all this content on the server rather than in the client via JS.
Finally, I think you can eliminate much of the content of your spans. You don't need an ID, you don't need arguments in your onclick(). Call a JS function which will figure out which node it's called from, go up one node to find the containing div and perhaps loop down the contained nodes and/or look at the text to figure out which item within a div it should be responding to. You can make the onclick handler do a whole lot of work - this work only gets done once, at mouse click time, and will not be multiplied by 2000x something. It will not take a perceptible amount of user time.
John Resig wrote a blog on documentDragments http://ejohn.org/blog/dom-documentfragments/
My suggestion is to create a documentDragment for each row and append that to the DOM as you create it. A timeout wrapping each appendChild may help if there is any hanging from the browser
function addRow(row) {
var fragment = document.createDocumentFragment();
var div = document.createElement('div');
div.addAttribute('class', 'b');
fragment.appendChild(div);
div.innerHtml = "<div>what ever you want in each row</div>";
// setting a timeout of zero will allow the browser to intersperse the action of attaching to the dom with other things so that the delay isn't so noticable
window.setTimeout(function() {
document.body.appendChild(div);
}, 0);
};
hope that helps
One other problem is that there's too much stuff on the page for your browser to handle gracefully. I'm not sure if the page's design permits this, but how about putting those 2000 lines into a DIV with a fixed size and overflow: auto so the user gets a scrollable window in the page?
It's not what I'd prefer as a user, but if it fixes the cursor weirdness it might be an acceptable workaround.
Yet Another Solution
...to the "too much stuff on the page" problem:
(please let me know when you get sick and tired of these suggestions!)
If you have the option of using an embedded object, say a Java Applet (my personal preference but most people won't touch it) or JavaFX or Flash or Silverlight or...
then you could display all that funky data in that technology, embedded into your browser page. The contents of the page wouldn't be any of the browser's business and hence it wouldn't choke up on you.
Apart from the load time for Java or whatever, this could be transparent and invisible to the user, i.e. it's (almost) possible to do this so the text appears to be displayed on the page just as if it were directly in the HTML.