Simple way to find html-element which has been rendered by React - html

For fast searching elements by Selenium, I think it must be a simple way to set some attributes to html-elements, for example: transform React Component Key to data-attribute (if it is possible).
Of course I can writing id or data-attributes to my span, div and whatever in my components, but I can't do it with components of 3d-party libraries - this components may haven't props like "id", and I will have to wrap this components and then find they by tag or class...
Or maybe is plugin for webpack to set data-attributes to elements with component's names.
However, how you find elements in your react app render?
I think it's not a good idea find elements by class or tags
key transform like this:
<MyComponent key="SuperComponent" />
...
<div data-attr="SuperComponent">...</div>
or autoset attributes of component name like this:
<MySuperComponent />
...
<div data-attr="MySuperComponent">...</div>

From "Test Automation through Selenium" perspective it hardly matters if the HTML consists of id or data-attributes. While working with Selenium tests are written with the help of any effective <tag> and the associated attributes. However there is a preferred list of Locator Strategies as follows:
How to find elements in react app render?
The AUT (Application Under Test) being ReactJS based of-coarse the element will be having dynamic attributes. Locator Strategies can also be dynamic. You can find an example usage of Dynamic Locator Strategies in the discussion How to locate a button with a dynamicID
Finally, while Test Automation the fast moving WebDriver instance will be needed to be synchronized with the lagging browser. You can find a relevant discussion in Do we have any generic funtion to check if page has completely loaded in Selenium

Related

JSoup Select Tag Recursive Search

I recently tried to work with JSoup to parse HTML documents, I went through the turorial on JSoup and found that the select-Method might be what I am looking for.
What I try to accomplish is to find all elements in a html document which possess a certain class. To test that, I tried this with the amazon web page (idea: find all deals with certain offers).
So I inspected the web page to see which classes and ids are being used and then I tried to integrate this into a small code snippet. In this example I found the follwing element:
<span id="dealTitle" class="a-size-base a-color-link dealTitleTwoLine restVisible singleCellTitle autoHeight">PROCAVE Matratzen-Brücke aus Schaumstoff 25 x 200 cm für ...</span>
This element is embedded in other elements and exists multiple times (for each deal of course). So here is my code to read the deal elements:
Document doc = Jsoup.connect("https://www.amazon.de/gp/angebote/ref=gbph_ftr_s-8_cd61_page_1?gb_f_LD=dealStates:AVAILABLE%252CWAITLIST%252CWAITLISTFULL%252CUPCOMING,dealTypes:LIGHTNING_DEAL,page:1,sortOrder:BY_SCORE,dealsPerPage:8&pf_rd_p=425ddcb8-bed4-4e85-ac0f-c1a79d14cd61&pf_rd_s=slot-8&pf_rd_t=701&pf_rd_i=gb_main&pf_rd_m=A3JWKAKR8XB7XF&pf_rd_r=BTHRY008J9N3N5CCMNEN&gb_f_second=dealStates:AVAILABLE%252CWAITLIST%252CWAITLISTFULL,dealTypes:COUPON_DEAL,page:8,sortOrder:BY_SCORE,dealsPerPage:8").timeout(0).get();
Elements deals = doc.select("span.a-size-base.a-color-link.dealTitleTwoLine.restVisible.singleCellTitle.autoHeight");
for (Element deal : deals) {
if (deal.text().contains("ItemMatch")) {
System.out.println("Found deal: " + deal.text());
}
}
Unfortunately I can't get the element I am looking for. deals has always the size of 0. I tried to modify my select with only part of the classes, I added the id-attribute and so on. Nevertheless, I do not get the elements (in this case these are nested into some others). If I try an element which is above this element in the DOM hierarchy (e.g. the div with class "a-section a-spacing-none slotContainer"), this is found.
Do I actually need to specify the whole DOM hierarchy (by using ">" in my select expressions? I expected to be able to define a selector and JSoup would travers and search the whole DOM-tree.
No, you do not have to specify the full DOM hierarchy. Your test should work, if the elements are really part of the DOM. I suspect that they might not be part of DOM as it is loaded be JSoup. The reason might me, that the inner DOM nodes are filled by JavaScript through AJAX. JSoup does not run JavaScript, so dynamically loaded parts of the DOM are not accessible. To achieve what you want you can either look into the AJAX calls directly and analyze them, or you move on to another solution like selenium webdriver, which runs a real browser including a working JavaScript engine.

How to find the element in this below case while working with selenium IDE

Firebug shows : <a class="ng-binding" ng-click="goto(menu.MenuInfo.Href)">
FirePath shows : html/body/nav/div[1]/div[1]/ul/li[3]/a
It shows as above when I use Firebug or FirePath to find the web element;
Then I copy it to Selenium IDE Target text and click the find button , But it cannot find the web element.
How can I find the web element and make it run in Selenium IDE to record script?
Automatic XPath detectors are usually not a good choice when trying to figure out the Selenium locator for a specific web element. Especially expressions with numeric indexes (e.g. your li[3]) are likely to change if list/table items are removed, added or resorted.
The best way to locate an element is always by id, as this is always unique (unless you have invalid HTML). But your element doesn't have one, unfortunately.
For <a> elements, it's usually good to use the LinkText for locating the element, provided that a) it's unique and b) your site doesn't have a language toggle functionality, which usually changes all link texts.
Alternatively, you could use the tag name and class via CSS selector:
a.ng-binding
Still, it depends on the structure of your page whether this locator is unique or not. There are no general rules for finding the best locator, just good and bad strategies.

Is it good practice to use attributes just to mark html elements?

I have a doubt about good practices writing HTML with Javascript.
I've came up with an idea (probably not the first, but couldn't find a clear reference about that) to mark some elements as candidates to load some data when it's available (after some user interaction). Let me exemplify:
Suppose I have a request that returns the following:
GET /animals/dog
{
name: "Gutemberg",
race: "doberman",
age: "2y"
}
The code I wrote binds fields in the response to elements that are candidates to load such value.
For example: With the request above, I could use the following tags:
<input name="dog-name-field" data-load-dog-name type="text"/>
<input name="dog-age-hid" data-load-dog-age type="hidden"/>
Each tag would receive the property value because it's marked as a candidate to do so - dog-name-field will have a value of "Gutemberg" when everything executes . That will happen everytime the request is reloaded. For now, I just get the data type I've searched ("dog"), concat it with the property "name/age" to form the attribute data-load-type-property and set a value to everyone that has such attribute.
I have a feeling that attributes are not meant to be used just like that, but I'm not aware of any real downsides to that. As I could not find it for the lack of a clear name to this approach, I'd like some guidance.
Is there a name for such technique? Is it a bad practice? If so, why?
PS:
To comply with SO good practices, I'd like the answers to be reference-guided and not based solely on opinion whenever possible. If no reference is provided, please, let us have a solid, well described example.
I have a feeling that attributes are not meant to be used just like that
Let's see what custom data attributes are meant to be used for:
Custom data attributes are intended to store custom data private to
the page or application, for which there are no more appropriate
attributes or elements. These attributes are not intended for use by
software that is independent of the site that uses the attributes.
(from w3.org)
So whether using data-attributes is "appropriate" in your case depends on your needs: if the DOM API doesn't provide better attributes to do that then it's appropriate.
If your need is just to select some element to change the textContent then you have two more appropriate/simpler options:
1) Using the id attribute if your elements are going to be unique in the document
The id global attribute defines a unique identifier (ID) which must be
unique in the whole document. Its purpose is to identify the element
when linking (using a fragment identifier), scripting, or styling
(with CSS).
(from id on MDN)
2) Using the class attribute if your elements are going to be used in multiple instances in the document
The class global attribute is a space-separated list of the classes of
the element. Classes allows CSS and Javascript to select and access
specific elements via the class selectors or functions like the DOM
method document.getElementsByClassName.
(from class on MDN)
As #Supr says in his answer, what you are doing is a very simple implementation of data-binding. data-binding can involve a lot more complexity than what you are doing at the moment; for example you may want to:
keep in sync your UI with a Javascript object which represent your business model instead of directly injecting data coming from an Ajax call,
update other attributes (value, style) and not only innerHTML or textContent,
have your business model updated in reaction to changes on the UI (two way data binding)
To implement all these features, simple id and class selectors are not sufficient, and this is why frameworks which implement data-binding, like KnockoutJS or AngularJS, use the more flexible data-* attributes instead (AngularJS is actually using its own ng-* attributes, but allows to use the alternative data-ng-* syntax for using HTML validation tools).
Data attributes allow to describe much more complex bindings:
<input data-bind="visible: editing, value: name, hasFocus: editing" />
Check KnockoutJS documentation for the meaning of the above code, it is not relevant to this example but just imagine describing that with classes or ids, it wouldn't be very convenient.
TL;DR
If you don't plan to implement more complex features you might want to use class and id instead.
This is called binding. Sometimes data binding and sometimes template binding.
Various frameworks provide mechanisms for this, though the syntax varies.
AngularJS example:
<input ng-model="dog.name" />
Knockout example:
<input data-bind="textInput: dog.name" />
React example:
<input value={this.state.dog.name} />
These are all quite popular frameworks/libraries, so I think it's safe to say it is not considered bad practice. The main difference from your approach is that they use the value of the attribute to specify the reference into the model (i.e. the "dog.name" part of your attributes), while you are putting the reference in the attribute name. In practice this is mostly a matter of style. Separating the reference from the "marker" (i.e. "data-load") is perhaps a bit more readable.

ASP.NET - Using HAP (HTML Agility Pack) to Add Class References During Render

Is it possible to use the HAP (HTML Agility Pack) to:
Grab a collection of nodes e.g. all <a> elements which are children of <li> elements
Iterate over the collection
Add CSS class references into the class attribute for each element e.g. class &= "foo"
Update the nodes in their original position within the HTML
For point 4, I need to know whether:
When I grab a collection of nodes, am I working with copies?
If so, can I easily update the nodes in their original position within the HTML
Finally, would it be practical to do this when rendering a page in an ASP.NET website, considering:
I will need to modify the class references for no more than 100
elements
I am not working with large HTML documents
I plan to select my nodes starting at a div e.g. div[2] where body
contains 4 divs
I realise that this may seem like a bunch of separate questions but really it is just a breakdown of the following two questions:
Can I easily modify the HTML output of an ASP.NET page e.g. to insert class references?
Would it be practical to do this on 50 - 100 elements WRT speed e.g. no more than 2 seconds cost?
Many thanks.
Check out my CsQuery project: https://github.com/jamietre/csquery or on nuget as "CsQuery".
This is a C# (.NET 4) port of jQuery. Selectors are orders of magnitude faster than HTML Agility Pack; in fact, my initial purpose in writing it was to do exactly what you want to do: manipulate HTML in real time. As it happens, from a CMS with html generated by ckeditor.
To intercept HTML in webforms with CsQuery you do this in the page codebehind:
using CsQuery;
using CsQuery.Web;
protected override void Render(HtmlTextWriter writer)
{
// the CsQueryHttpContext object is part of the CsQuery library, it's a helper
// than abstracts the process of intercepting base.Render() for you.
CsQueryHttpContext csqContext =
WebForms.CreateFromRender(Page, base.Render, writer);
// CQ object is like a jQuery object. The "Dom" property of the context
// returned above represents the output of this page.
CQ doc = csqContext.Dom;
doc["li > a"].AddClass("foo");
// write it
csqContext.Render();
}
There is basic documentation on GitHub, but apart from getting HTML in and out, it works pretty much like jQuery. The WebForms object above is just to help you handle interacting with the HtmlTextWriter object and the Render method. The general-purpose usage is very simple:
var doc = CQ.Create(htmlString);
// or
var doc = CQ.CreateFromUrl(url);
.. do stuff with doc, a CQ object that acts like a jQuery object
string html = doc.Render();
Don't do that ! ASP.NET is not meant to be used that way, there is a better ways to do this task depending on how do you create that markup in witch you want change or add css classes. ASP.NET uses aspx templates, basically html markup and there you can intervene with code executing on server, here you can set css class statically or use server side scripts to set css class on markup with some code.
You can also create controls in code behind and set css to controls if anchor control have parent that is list item control (you will have to use server side controls).
To do it your way you will have to make Response Filter (example here) and after request is done do your parsing and write results and changes back to response stream. It's much easier using common ASP.NET techniques.

Why does Wicket changes the id of the html elements?

If I write
<form wicket:id="form" id="form>
or even
<form wicket:id="form>...
Then the rendered HTML shows the id 'form' appended with different numbers whenever the page is refreshed e.g.
<form id="form7"....
Is there a way to disable this behavior of the Wicket framework?
We set markup ids by hand extensively on our project to ease automatic testing with Selenium testing framework. It definitely works.
Component.setOutputMarkupId(true); // write id attribute of element to html
Component.setMarkupId("someid"); // id attribute of element is "someid"
This is the behavior you want in most cases when using wicket. The dynamic id is meant to prevent id collisions when Ajax behaviors are added to components or added to ajax responses for refreshing. For any of these situations, you really need both the client response and the server side state to be in cahoots. If there are external js resources you need the id of a component for dom lookup, then I would suggest adding a custom wicket component behavior that would then generate the js call to a function passing in the generated id.
I realize what I'm going to describe leads you more into the forest of Wicket. But I have been more than happy with the ajaxy stuff that Wicket opens up for you out of the box.
This is Wicket desing feature. You can use class for linking styles and components.
<form wicket:id="form" id="form>
Also you can to try (I never did it) setMarkupId . I'm not sure that it good way.
It has been a while since I worked with Wicket, but I remember that when wicket uses ajax elements, its ids are auto-generated (the id of the tag, not the wicket:id). You can control the id of the tag when not using and ajax element. In your case, since there is no code, I would guess that you will have to change any AjaxButton or Ajax* from your form.
Yes you can write custom JavaScript... you just need to implement it according to the 'Wicket way'. You can decorate components, Ajax calls etc. with custom JavaScript, then it all plays nicely.