Automated material UI components using watir or selenium - watir-webdriver

I am trying to find out if anyone has an approach to automated UI testing on Material UI components.
Material UI elements are rendered as nested divs with very little unique id information, for example:
<div data-reactroot style="...">
<div style="...">
<div style="...">
</div>
</div>
</div>
The nested div structure makes using traditional location methods difficult if not impossible - (Selenium and Watir), id, name, class, etc.
Using react devtools, one can see a much clearer picture of how the page is structured, but I am not yet able to access the React "DOM" to locate elements.
Any ideas or help would be appreciated.
Added example:
Sliders
I can't come up with an example that is more descriptive than the one above, could literally be 10 layers of nested divs without any text.

There is no general method I'm aware of, unfortunately.
Some of the components already have ids, which allows you to use a css selector like #my-component input (which is usually enough to get an exact field), others have custom class names to be added (like AutoComplete - popoverProps) which allows you to use a similar selector.
Good news is that every MaterialUI component provides className, which can be used to locate elements (at least partially) - details can be found at http://www.material-ui.com/#/customization/styles
Also id field works quite often, even when not documented.
At the last resort (if detection by class + other css selector parts is not sufficient) you can fall back to XPath expression using element text - for example, I use //span[#class="menu-item"][.//div[contains(text(),"${itemName}")]] for matching menu items. It matches things declared as <MenuItem primaryText={itemName} className="menu-item">

Related

Getting an element defined in a core:html by its ID

I used this line to define a canvas element in my view.xml:
<core:HTML content="<div class="wrapper col-6"><canvas id="
myChart"width="800"height="400"></canvas></div>">
</core:HTML>
Now I want to get the element in the controller but the typical this.getView().byId("myChart") doesn't seem to work even though the site successfully loads a canvas with the ID.
Is there a way to get those types of elements defined inside a core:HTML tag for the controller?
If not, is there a different way to create a canvas or other HTML elements so that I can refer to them with an ID / use them in the controller?
The element created in this way is not 'registered' in UI5 framework like the other controls. byId() only checks the internal register.
You can use jQuery or standard JavaScript to fetch the element though, like $('#myChart') or document.querySelector('#myChart').
You will find the code for this in Core.js or Core-dbg.js.
Like Jorg said, byId is for retrieving controls. So if you were to put an id on the HTML control, you could retrieve that control and then call getDomRef() on it to get the outermost element, which in your example would be the div. If you'd further only put the canvas inside the HTML control, you'd get that.
If you're accessing the id of the canvas directly, like Jorg suggested, you'll run into trouble if you're going to use the view twice inside a page, because the id of the canvas isn't unique anymore.
There is a third and IMHO preferable option, that is to use html directly inside the view. First you'll need to declare a namespace for it, like
xmlns:html="http://www.w3.org/1999/xhtml"
preferably right on your View element.
Then you can write html directly in your xml view like this:
<html:div class="wrapper col-6">
<html:canvas id="mycanvas" width="800" height="400"></html:canvas>
</html:div>
This way you're getting a proper (unique) id for your canvas and can access it as part of the view's dom with this.getView().getDomRef("-mycanvas"). Note the extra leading dash, because of internal id generation inconsistency in UI5. Also note that getDomRef() is considered protected, but I doubt it will change. Finally, remember that you can only get a domref for rendered controls, so you'll probably want to access it from an afterRendering event.

Joomla 'PageNavigation' Plugin

If this isn't possible please let me know!
I'm hoping there's a solution to what I'm asking.
I need to move the Next/Prev buttons, located in the pagenavigation plugin to after the <jdoc:include type="component" />; Basically render it anywhere in my templates' index.php?
Is there any way to do this?
This is the code that renders the pagination:
<?php
if (!empty($this->item->pagination) && $this->item->pagination && $this->item->paginationposition && !$this->item->paginationrelative):
echo $this->item->pagination;
?>
<?php endif; ?>
As you can see the pagination is part of the item. As you can see if you look at the pagenavigation content plugin the pagination values are created in response to the onContentBeforeDisplay event. The plugin is hard coded to only work for articles in the single article view.
So to use it in a different component you would really need to create a second plugin for that component (or you could do any component or anything besides the single article view, that all would be easy to code using context).
To locate it in a different place in the single article view you would have to move the block of code to the desired location in the layout. Potentially you could also use css to locate the rendering of the block somewhere else on the page. (But more on this at the bottom.)
Unfortunately (but nor surprisingly given its name) onContentBeforeDisplay comes really late, in the view (unlike with pagination in the backend).
I always find it confusing because this frontend "pagination" property controlled by this plugin has nothing to do with backend pagination which is controlled by a JPagination object. I believe if is because of backward compatibility all the way to 1.0. ALso because the template chrome for pagination chrome are called pagination.php.
That leads me to the next thing I'll mention. You can make a file pagination.php and put it in the html folder of your template. You can see an example of this in the core template protostar. THat's where you would do the CSS or whatever other tricks you want to do to make the pagination do what you want. I think if you work hard enough at it (possibly using javascript or possibly calling that file from a module) you can pretty much achieve whatever you want.

Variables in UIBinder xml

I am new to GWT and can not find an answer to this: I have got a nice UIBinder for a TextBox, it works, I have UIHandler working with it, ok. But what if I want to show a value from this TextBox all over my HTML? Is there a way to declare one variable to reuse this value all over HTML, or should i declare new Label with new ui:field name every time I want to show the value on one html page, and fill every such a Label with UIHandler (wich I could do right away, but this seems really boring)?
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:HTMLPanel>
<g:TextBox ui:field="myField"/><br/>
<div>
<p>
What do I need to put here if i want to see **myField.getValue()** in html, may be even multiple times?
And **here**?
I want to avoid creation of new and new objects in back-end class for just one value, multiple labels here are ok. How to push one value in all of them, when myField content is changed?
</p>
</div>
</g:HTMLPanel>
There are two approaches to designing GUI in code in MVC (whatever that means) way:
GUI is smart and pulls data from model, usually when certain events happen (data binding falls into this category),
GUI is stupid, so the data is pushed into view by a controller (it is sometimes called a passive view).
Both have their pros and their cons, but the important thing is: when you try to combine them, the pros cancel each other, and cons - accumulate. That is you end up with disadvantages of each pattern and a big mess.
UIbinder is a tool that helps you build a stupid view, as used in MVP pattern. It helps you easily create a bunch of objects that will redraw parts of view when you push data into them. They are not supposed to be intelligent entities. So the boring way seems to be the way to go.
Not wanting to use a label is, btw, a little strange: you need an object to update parts of the ui (it's Java, using objects is what we do!). It just so happens that such type of object exists and is called Label. Would you like it more if the very same class was called AnAutomaticHtmlUpdaterThatRequiresNoLabelWhatsoever?

jQuery Show/Hide divs using same class not working because of html.push?

The object is to Show-Hide text located under their respective Titles, so a User reads the title and shows or hides text belonging to that title if the User wants to read more.
I tried whatever I could find so far on here, we're talking dynamically setting text coming from a spreadsheet, can't use IDs, must work with .class, must be missing something, I have this piece of code:
... html.push('<div class="comments">' + comment + '</div></div></div>');
but when I try this Show-Hide code nothing happens, even if the error console shows nothing. Basically I want to Show-Hide the .comments class divs with a show-hide toggle link located under each of them. I say them because the .comments divs are reproduced dynamically while extracting text coming from Google spreadsheet cells/row (one .comments div per spreadsheet row). I tried .next, child and parent but they all divorced me so I dunno looks like a dynamic issue. So far I only managed to globally toggle all divs to a visible or hidden state but I need to toggle independantly individual divs.
I prefer a jQuery solution but whatever worked so far was achieved with native javascript.
Note: If a cross-browser truncate function which would append a more-less link after a number of words (var) in each .comments divs would be easier to implement then I would gladly take that option. Thx for any help, remember I am still learning lol!
I have been working on an entirely JS UI project and have brought myself to using $('', { properties }).appendTo(BaseElement) to work best for adding HTML elements because it appropriately manipulates the DOM every time.
If you are having good luck with push elsewhere, however, breakpointing on the line where you do your $('.class').hide() and see what $('.class').length is. Alternately, you can just add alert($('.class').length) to your code if you are unable to breakpoint the code. If it is 0, then your elements have not been properly added to the DOM. Changing to append will ensure they are part of the DOM and therefore targetable via JQuery.

How to handle html templates in MVC2?

My (MVC2) application displays several addresses in a View.
Each address contains just a subset of information, like first- and lastname. The request is that the complete address information should be displayed when the mouse is over a result.
An html template should be used therefor.
This template defines how(!) the complete address should be displayed – but it doesn’t defines what(!) should be displayed.
Means it can be assumed that the complete address is always “firstname“, “lastname”, “street”, “zipcode” and “city” (for example and to keep it simple). This will never be changed.
But for example the background color can be changed in the html template from white to green or the size of the lastname can be changed from <h1> to <h2> …
What is the best way to solve it?
I would prefer to write some shared code (keyword: ascx).
This shared code should wrap the template, would be very easy and would look like this:
<div id=”mouseOver” style="display: none;" >
X_REPLACE_X
</div>
The template would look like this simplified example:
FirstName: {Name}<br/>
Lastname: <h1>{Lastname}/<h1><br/>
ZipCode: {ZipCode}<br/>
I would then render the ascx code via “Html.RenderPartial” on the View and map each address to a javascript mouseover function.
The javascript function would replace the placeholder (like {FistName}, {LastName} , etc.) in the template, position and display it.
And thats my problem:
The template should NOT be put directly in the wrapper (ascx - code)!
Means at runtime must “X_REPLACE_X” be replaced with a somewhere on the server stored template.
Because this gives me the ability to change the template without changing and publishing the code!
How can this be managed?
Is there a much better way to solve it? Should I use instead ajax calls to get the template in a variable?
Any help would be really great!
thxs in advance!
It sounds like the best way to accommodate your display differences is to simply use different css classes. The html template used for the full information does not change and can be used for all addresses, while the differences between background colors and text size can be handled by different css settings.
Relatedly, I wouldn't handle the different text sizes by using <h1></h1> and <h2></h2> but rather a common tag (such as <span></span>) whose text size is handled via css.