How to get value from a div with no ID using Selenium - javascript

I am using the Selenium WebDriver Java API on a Java/HTML5 web project. We do not use many IDs, so I am using xPath to isolate values. In the following HTML snippet, when I use my normal method to grab values, the label and the value text are returned.
<div class="gf-item col-sm-4"><label>First Name</label>Emma</div>
Is there an elegant way to grab just the value ("Emma") using Selenium?
Thanks!

I believe the XPath would be
//div[#class="gf-item col-sm-4"]/label/following-sibling::text()

There may be a prettier approach to this. I would create two selectors. One that returns only what you want to exclude and one that returns what you want and what you don't. Then use some Java to compare and remove what you don't want. I don't do xpath so this is all css selectors.
First, the 'big' selector - returns 'First NameEmma'
$$("div.gf-item")
Then the 'trim' selector to define what we don't want - returns 'First Name"
$$("div.gf-item>label")
Then some Java to compare and remove the 'extra' stuff. This removes 'First Name' and leaves only 'Emma'.
String big = getText(big);
String trim = getTextText(trim);
String desiredText = big.replaceAll(trim, "");

Related

How to find two web objects with the same properties using JavaScript for Test Automation

I have this piece of HTML codes
I need to find those 2 objects using JavaScript so I can click() it and write some text (Test Automation).
The issue is the id is dynamically generated, thus can't be used because it keeps changing everytime the page loads. Now because the id can't be used , those 2 objects looks the same without any unique identifier.
If I use this
document.querySelector("input.value-restored[type='text']");
Then it will just find the first one.
Any idea how can I hit both objects?
Thank you.
You can use [contains()] to construct a xpath for these elements. As I can see the parent span has a stable class name which you can use.
in JAVA
WebElement firstElement = driver.findelements(By.xpath("//span[contains(#class,'form-row-ui-calender-row')]/input[#type='text']")).get(0);
WebElement secondElement = driver.findelements(By.xpath("//span[contains(#class,'form-row-ui-calender-row')]/input[#type='text']")).get(1);
OR use indexing with your xpath.
WebElement firstElement = driver.findelements(By.xpath("//span[contains(#class,'form-row-ui-calender-row')]/input[#type='text'][1]"));
WebElement secondElement = driver.findelements(By.xpath("//span[contains(#class,'form-row-ui-calender-row')]/input[#type='text'][2]"));
Hope this helps.
Try this way.
Use indexing after complete your xpath. Inside below xpath [2] indicates second input webelement. If there are multiple input tag is available then you should use of indexing.
//input[#class='ui-calendar-display widget has-change-tracker value-restored'][2]
If you want to locate first webelement then use below xpath.
//input[#class='ui-calendar-display widget has-change-tracker value-restored'][1]
In TestComplete, you can do this in the following way (within script):
let obj = page.FindChildByXPath('//span[text()="Date to:"]/following-sibling::span/input[contains(#class, "ui-calendar-display")]', false);
obj.Click();
If you are using Name Mapping, you can map this object quite reliably using the Required Children feature and access the object directly by a name from the mapping tree. Let me know if you need more details on how to create such mapping.

Using variables with jQuery's replaceWith() method

Ok this one seems pretty simple (and it probably is). I am trying to use jQuery's replace with method but I don't feel like putting all of the html that will be replacing the html on the page into the method itself (its like 60 lines of HTML). So I want to put the html that will be the replacement in a variable named qOneSmall like so
var qOneSmall = qOneSmall.html('..........all the html');
but when I try this I get this error back
Uncaught SyntaxError: Unexpected token ILLEGAL
I don't see any reserved words in there..? Any help would be appreciated.
I think the solution is to only grab the element on the page you're interested in. You say you have like 60 lines. If you know exactly what you want to replace..place just that text in a div with an id='mySpecialText'. Then use jQuery to find and replace just that.
var replacementText = "....all the HTML";
$("#mySpecialText").text(replacementText);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mySpecialText">Foo</div>
If you're only looking to replace text then jaj.laney's .text() approach can be used. However, that will not render the string as HTML.
The reason the way you're using .html() is likely illegal is that qSmallOne is not a JQuery object. The method cannot be performed on arbitrary variables. You can set the HTML string to a variable and pass that string to the .html() function like this:
var htmlstring = '<em>emphasis</em> and <strong>strong</strong>';
$('#target').html(htmlstring);
To see the difference between using .html() and .text() you can check out this short fiddle.
Edit after seeing the HTML
So there is a lot going on here. I'm just going to group these things into a list of issues
The HTML Strings
So I actually learned something here. Using the carriage return and tab keys in the HTML string is breaking the string. The illegal-ness is coming from the fact the string is never properly terminated since it thinks it ends at the first line. Strip out the white space in your strings and they're perfectly valid.
Variable Names
Minor thing, you've got a typo in qSmallOne. Be sure to check your spelling especially when working with these giant variables. A little diligence up front will save a bunch of headache later.
Selecting the Right Target
Your targets for the change in content are IDs that are in the strings in your variables and not in the actual DOM. While it looks like you're handling this, I found it rather confusing. I would use one containing element with a static ID and target that instead (that way you don't have to remember why you're handling multiple IDs for one container in the future).
Using replaceWith() and html()
.replaceWith() is used to replace an element with something else. This includes the element that is being targeted, so you need to be very aware of what you're wanting to replace. .html() may be a better way to go since it replaces the content within the target, not including the target itself.
I've made these updates and forked your fiddle here.

Loop though DOM with jQuery to get some data- attribute value

This seems like a simple thing, but I keep getting "undefined"
I am trying out the "data-" HTML5 attribute and I am looping through a bunch of div tags that look like this:
<div id="myEvent"
data-scheduledOn="1399985100000"
data-eventStatus="3">
And I am looping through a bunch of these like this:
$('[id="myEvent"]').each(function(index, divItem) {
alert($(divItem).data("scheduledOn"));
}
But I keep getting "undefined" If I do this (get the attribute) it works fine:
alert($(divItem).attr("data-scheduledOn"));
So What am I missing?
http://api.jquery.com/data/
"The .data() method allows us to attach data of any type to DOM elements in a way that is safe from circular references and therefore from memory leaks."
At least at this point in time, to use the .data function you have to attach the data using the function before you can read it back using the .data function.
If you need to read pre-existing data use the .attr or .prop functions.
It seems as though It is a naming problem as Hamza Kubba suggested, but just a bit different...
if I changed the name of the data attribute to "data-scheduled-on" I can retrieve it by .data("scheduledOn") OR using data-scheduledon and .data("scheduledon") also works.
So don't use CAPS for data- names is the moral of this story!
Please note that per HTML 5 specs, the attribute name should not contain any uppercase letters and some browsers such as FF & Chrome will change any uppercase letter to lowercase. That's why the following demo works if you access the data attributes with lowercase names:
http://jsfiddle.net/fiddleyetu/5LdQd/
$('div.myEvent').each(function(index, divItem) {
console.log($(divItem).data("scheduledon"));
console.log( $(divItem).data("eventstatus") );
});
Ans since you cannot have more than one element on a page with the same ID, I have used a class selector for the demo.
MORAL: Do not use UPPERcase; your browsers may not always be that 'understanding'.

JQuery: What's the difference between referencing an element using #[objectId] or [id=objectId]

Can anybody tell me what's the difference between referencing an element using #[objectId] or [id=objectId]?
The first one is very fast, as jQuery internally uses getElementById when it recognizes the pattern (using a regular expression).
The second one asks jQuery to iterate over all objects having an id. It's very slow. jQuery doesn't even stop iterating when it find one match in that case.
The only legitimate reason to use a [id... selector is when you don't just search by an exact id, for example you might want to search all elements whose id starts with "something" using $('[id^=something]').
Assuming you have a valid HTML (no reused id) and a valid id, you can still have problems with $('#'+someId) (for example when your id contains a quote, or anything that breaks Sizzle's pattern recognition system). In that case, use $(document.getElementById(someId)).
Following your comment : Yes, a "#" in an ID makes it impossible for Sizzle (jQuery's selector engine) to understand your selector. Sizzle uses the following regex :
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
and /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/.test('#som#thing') returns false.

Select class name (number) using RegEx & Jquery

I have a element like this
<div class="th-class2 th-hhjjsd th-context-78474378437834873"></div>
(Note: I know class names should not be pure numbers)
I want to get the numerical number from this div.
id = 78474378437834873
Is there a way I can use regular expressions to do it. I am nearly there but it only returns the first 4 numbers.
I use a clickevent to target the div and try and get the class like this
var classString = $(this).prop("class").match(/([0-9]+)/)[1];;
console.log(classString)
result is 7847
I am just not understanding how to get the rest of the number.
Thanks
You shouldn't use integers for class names because using a class typically means you are going to use the element more the once and adding a dynamic number defeats the purpose of classes, also working with someone else code and they use integers it's very hard to understand their code. As far as your questions goes, you shouldn't really use regular expressions to get a value of a class you should either store the value as an id so your element would look like this,
HTML
<div id="78474378437834873" class="th-class2 th-hhjjsd"></div>
or you could use a data object which is how I would do it like so,
HTML
<div class="th-class2 th-hhjjsd" data-object='{"value":78474378437834873}'></div>
and then when you select your element with your click event to get the value of the element you clicked console log the elements data object like so
jQuery
$('.th-class2').click(function() {
console.log($(this).data('object').value);
});
You should not use number only class names, they must start with an Alpha character [a-Z]
You can find what are the allowed characters in this discussion: Which characters are valid in CSS class names/selectors?
(Please make sure to read also the comments).
As per a solution for you,
The easy solution would be to use data attributes as so:
<div data-id="1000"></div>
and then you could get your id as simple as:
$(this).on('click', function() { console.log($(this).data('id')); } );
Happy Coding.

Categories

Resources