Selenium: How to assert all checkboxes checked? - xpath

Decimal totalCheckboxes = selenium.GetXpathCount("//input[#type='checkbox']");
for (int i = 1; i < totalCheckboxes + 1; i++)
{
// Assert attempt 1
//Assert.IsTrue(selenium.IsChecked("/descendant-or-self::input[#type='checkbox'][" + i + "]"));
// Assert attempt 2
//Assert.IsTrue(selenium.IsChecked("//input[#type='checkbox'][" + i + "]"));
}
I need to assert multiple checkboxes are checked. The number of checkboxes are not always fixed because they depend on my search criteria. Also, the checkboxes have different id and name. For example, for the first checkbox, id = "ctl07_ctl01_ctl01_cbxRepeater_e5962e80-ca07-42e3-908f-1217ef5787d4" name = "ctl07$ctl01$ctl01$cbxRepeater_e5962e80-ca07-42e3-908f-1217ef5787d4"
and for the second checkbox, id="ctl07_ctl01_ctl03_cbxRepeater_c094f428-7ead-4ded-a11b-5824be49a95b" name="ctl07$ctl01$ctl03$cbxRepeater_c094f428-7ead-4ded-a11b-5824be49a95b"
and so on for the following checkboxes.
I have tried several things to add an assertion to assert the checkboxes are checked (Assert attempt 1 and Assert attempt 2 above), but when I run the test, it still fails at that point. Ther error I get:
Selenium.SeleniumException: ERROR: Element /descendant-or-self::input[#type='checkbox'][1] not found
Selenium.SeleniumException: ERROR: Element //input[#type='checkbox'][2] not found
Any help on this would be highly appreciated. Thanks in advance!

Try :
Assert.IsTrue(selenium.IsChecked("xpath=(//input[#type='checkbox'])[" + i + "]"));
Note the addition of ().
The () says evaluate me first (as you would expect). This allows you to do (...)[1] to find the first element of the xpath evaluated in the ().

Related

Protractor - Unable to loop every item by using ElemArrayFinder each

I am using Protractor + Jasmine.
I have 2 elements (links) in a table, and I need to delete one after one - Or one-by-one. After I deleted the first item, the table will refresh and re-populated with the remaining elements (or links).
My code below only deleting the first element and exiting the code. I am unable to loop and delete all elements.
I am getting the total count correct.
element.all(by.xpath("//span[#class='abc']")).count().then(function (count)
{
element.all(by.xpath("//span[#class='abc']")).each(function (elem, index)
{
elem.getText().then(function (name)
{
console.log("NAME IS " + name);
var row = element(by.xpath('//span[contains(text(),"' + name + '")]/../../..'));
row.click();
var overFlow = element(by.xpath('//span[contains(text(),"' + name + '")]/../../..//*[#class="zzz"]'));
helper.clickElemWithJavascript(overFlow);
helper.scrollIntoView(deleteButton);
helper.clickElemWithJavascript(deleteButton);
})
})
}); //count
Promises chaining is one solution for this kind of issues.
I figured it out in this way and this is my approach:
I made these steps as a function.
I get the total count of elements using element.all().each(). This returns array of elements/array of values.
Using a For loop and length of the above array, calling the function (step 1) which has steps to delete Single element.
I followed Promises chaining. So unless the previous step was not finished, control flow will not execute the next step.
I am not familiar with Async and Await, so I followed the approach above.

How to return X elements [Selenium]?

A page loads 35.000 elements, which only the first 10 are of interest to me. Returning all elements makes the scraping extremely slow.
I only succeeded in either returning the first element with:
driver.find_element_by
Or returning all, 35.000 elements, with:
driver.find_elements_by
Anyone knows a way to return x amount of elements found?
Selenium does not provide a facility that allows returning only a slice of the .find_elements... calls. A general solution if you want to optimize things so that you do not need to have Selenium return every single element is perform the slice operation on the browser side, in JavaScript. I present this solution in this answer here. If you want to use XPath for selecting the DOM nodes, you could adapt the answer here to that, or you could use the method in another answer I've submitted.
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("http://www.example.com")
# We add 35000 paragraphs with class `test` to the page so that we can
# later show how to get the first 10 paragraphs of this class. Each
# paragraph is uniquely numbered.
driver.execute_script("""
var html = [];
for (var i = 0; i < 35000; ++i) {
html.push("<p class='test'>"+ i + "</p>");
}
document.body.innerHTML += html.join("");
""")
elements = driver.execute_script("""
return Array.prototype.slice.call(document.querySelectorAll("p.test"), 0, 10);
""")
# Verify that we got the first 10 elements by outputting the text they
# contain to the console. The loop here is for illustration purposes
# to show that the `elements` array contains what we want. In real
# code, if I wanted to process the text of the first 10 elements, I'd
# do what I show next.
for element in elements:
print element.text
# A better way to get the text of the first 10 elements. This results
# in 1 round-trip between this script and the browser. The loop above
# would take 10 round-trips.
print driver.execute_script("""
return Array.prototype.slice.call(document.querySelectorAll("p.test"), 0, 10)
.map(function (x) { return x.textContent; });;
""")
driver.quit()
The Array.prototype.slice.call rigmarole is needed because what document.querySelectorAll returns looks like an Array but is not actually an Array object. (It is a NodeList.) So it does not have a .slice method but you can pass it to Array's slice method.
Here is a significantly different approach presented as a different answer because some people will prefer this one to the other one I gave, or the other one to this one.
This one relies on using XPath to slice the results:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("http://www.example.com")
# We add 35000 paragraphs with class `test` to the page so that we can
# later show how to get the first 10 paragraphs of this class. Each
# paragraph is uniquely numbered. These paragraphs are put into
# individual `div` to make sure they are not siblings of one
# another. (This prevents offering a naive XPath expression that would
# work only if they *are* siblings.)
driver.execute_script("""
var html = [];
for (var i = 0; i < 35000; ++i) {
html.push("<div><p class='test'>"+ i + "</p></div>");
}
document.body.innerHTML += html.join("");
""")
elements = driver.find_elements_by_xpath(
"(//p[#class='test'])[position() < 11]")
for element in elements:
print element.text
driver.quit()
Note that XPath uses 1-based indexes so < 11 is indeed the proper expression. The parentheses around the first part of the expression are absolutely necessary. With these parentheses, the [position() < 11] test checks the position each node has in the nodeset which is the result of the expression in parentheses. Without them, the position test would check the position of the nodes relative to their parents nodes, which would match all nodes because all <p> are at the first position in their respective <div>. (This is why I've added those <div> elements above: to show this problem.)
I would use this solution if I were already using XPath for my selection. Otherwise, if I were doing a search by CSS selector or by id I would not convert it to XPath only to perform the slice. I'd use the other method I've shown.

Mathematica Do/For loop with "Delete" or "Drop" does not work

initlNum453 = List[];
num1 = 2;
(*Pt1, initial work to make initlNum full of good variables*)
algorithmicNum = 1;
For[i7 = 1, i7 <= (num1 + 1)^2, i7++,
AppendTo[initlNum453, algorithmicNum];
If[((algorithmicNum) == (num1 + 1)), algorithmicNum = 1,
algorithmicNum++];
];
(*Pt2, delete unneeded variables*)
deleteValue = 1;
Do[
Delete[initlNum453, deleteValue];
deleteValue = (deleteValue + num1 + 2);
, {num1 + 1}
]
Here's a snippet of the code I'm trying to make (it involves pseudo-automating Lagrange polynomials). It should be simple; the first part creates a series of numbers in a list, and then the second should be delete a particular section (e.g., the 1,4,7 if n=2).
For some reason, one of the following occurs:
No Error, but the elements in the list remains the same/no elements get deleted
Taking out the semicolon says that the "Tag Times in ___ is Protected"-- can someone explain what exactly this means?
When putting this into a Module, the error states that the expression .' cannot be used as a part specification. Use Key[.`] instead.
In any case, I don't understand why something as simple as this is just doesn't work on Mathematica. The "Delete" function works outside of a for/do loop, but doesn't inside-- can someone explain why or tell me what I did wrong?
Thanks for your help! I appreciate it!
You need to write something like
initlNum453 = Delete[initlNum453, deleteValue]

Range of doubles in Swift

I am currently writing a Swift application and parts of it require making sure certain user inputs add up to a specified value.
A simplified example:
Through program interaction, the user has specified that totalValue = 67 and that turns = 2. This means that in two inputs, the user will have to provide two values that add up to 67.
So lets say on turn 1 the user enters 32, and then on turn 2 he enters 35, this would be valid because 32 + 35 = 67.
This all works fine, but the moment we verge into more than one decimal place, the program cannot add the numbers correctly. For example, if totalValue = 67 and then on turn 1 the user enters 66.95 and then on turn 2 he enters .05 the program will return that this is an error despite the fact that
66.95 + .05 = 67. This problem does not happen with one decimal place or less (something like turn 1 = 55.5 and turn 2 = 11.5 works fine), only for two decimal spots and beyond. I am storing the values as doubles. Thanks in advance
Some example code:
var totalWeights = 67
var input = Double(myTextField.text.bridgeToObjectiveC().doubleValue)
/*Each turn is for a button click*/
/*For turn 1*/
if inputValid == true && turn == 1 && input < totalWeights
{
myArray[0] = input
}
else
{
//show error string
}
/*For turn 2*/
if inputValid == true && turn == 2 && input == (totalWeights - myArray[0])
{
myArray[1] = input
}
else
{
//show error string
}
If you want exact values from floating point then the float/double types will not work, as they are only ever approximations of exact numbers. Look into using the NSDecimalNumber class from within Swift, I'm not sure what the bridging would look like but it should be simple.
Here is an example of how this could work:
var a = 0
for num in numlist {
a += num
}
var result = false
if a == targetnum
result = true
I haven't tested this out, but if numlist is an array of double then it should work for any input that is a valid number.
One problem I just realized is that there is an issue with doing an equals with doubles, as rounding will cause problems for you. I am not going to show it, but if, while reading in the inputs you keep track of how many numbers to the right of the decimal place, then multiply all of the values by that number of tens, so 66.95 * 100 to get it all as an integer, then add, then do the comparison, after multiplying the targetnum by the same value (100).
Unfortunately there is no ideal solution to this. We must use approximation type comparison.
For example, instead of checking:
if val1 == val2
we must try something like:
if val1 > (val2 - .0005) && val1 < (val2 + .0005)

Conditional Count inside of Group in .rdlc?

I have a .rdlc report, grouped.
Inside each group, I have an Id. Some of them will be positives, and others will be negative.
I need the difference between de quantity of positives Id's and negatives Id's
Something like
=CountDistinct(Fields!Id.Value) where Fields!Id.Value > 0 - CountDistinct(Fields!Id.Value) where Fields!Id.Value < 0
How Can I do that ? I'm thinking on a function, but I want to know if there is a simply way
Edit: An Id can be more than once time in each group, that's why I use CountDistinct
You can try this:
CountDistinct(IIf(Fields!Id.Value > 0, Fields!Id.Value, Nothing))
create 2 global variables. one for positive and one for negative.
Then create a new formula that counts them like the following:
WhilePrintingRecords;
IF (GroupName ({your_group_name}) > 0) THEN
Positive var = Positive var + 1;
ELSE
Negative var = Negative var + 1;
You can actually look for your group in the formulas and drag it to the editor while writing the formula.
Since its a operation in group level, the records should be read first. Thats why we use whilePrintingRecords rather than whileReadingRecords.
Hope I understood your question right.

Resources