Checking for readonly in Geb - groovy

I'm trying to write a test in Geb that has a bunch of different text fields. The scenario is essentially that there are five or six html inputs and the user should only be allowed to type in one of them at a time. That is, if the first textbox has a value, the rest of the boxes should be immutable.
Instead of the element having an input type="disabled", they have an attribute (I'm assuming it's an attribute?) of readonly.
Here is a generic example:
<input aria-labelledby="Date Input Value 1" id="Date Input 1" name="Date Input 1" class="input-small DateOrEmpty dateInput" value="" style="display: inline-block;" readonly="">
I've tried
${"input", id: "Date Input 1"}.#readonly
as well as
${"input", id: "Date Input 1"}.has("readonly")
and I haven't had much luck..

Instead of having to deal with the fact that even an empty readonly attribute will cause the element to be read only but $("input[id='Date Input 1']").#readonly evaluates to a falsey value (as #readonly returns the value of the attribute which is an empty string in your case) why not turn the navigator into an instance of FormElement module and use the isReadOnly() property method it provides?
$("input[id='Date Input 1']").module(FormElement).readOnly
EDIT
As pointed out by kriegaex, $("input[id='Date Input 1']").#readonly actually evaluates to a truthy value (because WebDriver always returns a string which contains true when obtaining the value of readonly attribute as long as the attribute is defined on the element and regardless of the actual value of that attribute).
The above means that:
$("input[id='Date Input 1']").module(FormElement).readOnly
and:
$("input[id='Date Input 1']").#readonly
are equivalent in that they evaluate to a truthy value.

You have several problems here:
You use HTML IDs with inline spaces. This are actually not legal names and make it more difficult to write simple CSS selectors like #my-id for them.
Geb syntax for selectors uses parentheses, not curly braces. Curly braces are used for closures, which are a completely different kind of beast.
Please note that according to HTML specification the readonly attribute is boolean and always true if it exists at all, i.e. usually you do not write readonly="something" but just readonly. Even if you write readonly="false" it will evaluate to true because its value is ignored, only its existence is checked.
So if you have this HTML code:
<input id="Date Input 1" readonly>
<input id="Date Input 2">
<input id="date-input-3" readonly="false">
<input id="date-input-4">
<input id="date-input-5" readonly="">
You can write these selectors in your Geb test (please note how not using spaces in IDs makes the selectors simpler):
$("input[id='Date Input 1']").#readonly
!$("input[id='Date Input 2']").#readonly
$("input#date-input-3").#readonly
!$("input#date-input-4").#readonly
$("input#date-input-5").#readonly

Related

"This JSX tag's 'children' prop expects a single child of type 'ReactNode'" error when inserting JS

So I have this piece that based on the showHistory boolean should show a piece of text.
{props.showHistory && <Typography variant="body1">Your previous score was: </Typography>}
But when I want to add a variable like this:
{props.showHistory && <Typography variant="body1">Your previous score was: {props.lastScore} </Typography>}
It gives me the error "This JSX tag's 'children' prop expects a single child of type 'ReactNode', but multiple children were provided.ts(2746)". I could come up with a work-around I think, but I want to understand what exactly goes wrong here and how to fix it.

Find if text exist inside a nested Div, if yes print out the whole string, Selenium Python

i'm very new to selenium(3.141.0) and python3, and i got a problem that couldn't figure it out.
The html looks similar to this
<div class='a'>
<div>
<p><b>ABC</b></p>
<p><b>ABC#123</b></p>
<p><b>XYZ</b></p>
<div>
</div>
I want selenium to find if # exist inside that div, (can not target the paragraph only element because sometime the text i want to extract is inside different element BUT it's always inside that <div class='a'>) If # exist => print the whole <p><b>ABC#123</b></p> (or sometime <div>ABC#123<div> )
To find an element with contained text, you must use an XPath. From what you are describing, it looks like you want the locator
//div[#class='a']//*[contains(text(),'#')]
^ a DIV with class 'a'
^ that has a descendant element that contains the text '#' within itself or a descendant
The code would look something like
for e in driver.find_elements(By.XPATH, "//div[#class='a']//*[contains(text(),'#')]"):
print(e.get_attribute('outerHTML')
and it will print all instances of <b>ABC#123</b>, <div>ABC#123</div>, or <p>ABC#123</p>, whichever exists

Long Integers are converting to scientific notation - ColdFusion

I am trying to pass a struct through a function, but the integers in it are converting to scientific notation.
Before deSerialization :
{"businessUnitValidList":2003051509034372557922
, "shortMessage":"Success"
, "longMessage":"Request Completed Successfully."
, "status":20001
}
After deSerialization:
businessUnitValidList 2.00305150903E+021
I have tried converting it into a string but it still gives me the same output. Any ideas?
Note: If I have more than one value in my businessUnitValidList, the numbers show up the way they are supposed to.
EDIT
This is the current code iteration:
<cfloop array="#businessUnitArray#" index="i">
<cfquery name="validatebusinessUnit" datasource="dbproduction">
select doctorid from survey.dbo.clientLocationMap
where clientbrandid = '#arguments.clientBrandid#'
and clientLocation = '#i#'
</cfquery>
<cfif validatebusinessUnit.recordcount gt 0>
<cfset businessUnitValidList = listAppend(businessUnitValidList,toString(validatebusinessUnit.doctorid),",")>
<cfelse>
<cfset businessUnitInValidList = listAppend(businessUnitInValidList,i,",")>
</cfif>
</cfloop>
<cfif businessUnitInValidList neq ''>
<cfset ResponseStruct['BusinessUnitCodes']['businessUnitMixResponse']['businessUnitInValidList'] = "#businessUnitInValidList#">
<cfset ResponseStruct['BusinessUnitCodes']['businessUnitMixResponse']['businessUnitValidList'] = "#businessUnitValidList#">
<cfreturn serializeJSON(ResponseStruct['BusinessUnitCodes']['businessUnitMixResponse'])>
<cfelse>
<cfset ResponseStruct['BusinessUnitCodes']['businessUnitSuccess']['businessUnitValidList'] = "#businessUnitValidList#">
<cfreturn serializeJSON(ResponseStruct['BusinessUnitCodes']['businessUnitSuccess'])>
</cfif>
ColdFusion's JSON serialization has issues and can vary between versions and even hotfixes. As Jedihomer Townend mentioned in the comments a leading space should force CF to treat it a string and not cast it.
I've just tried this on CF10, 11 and 2016 and preserves the input.
<cfscript>
a = {
"businessUnitValidList":" 2003051509034372557922",
"shortMessage":"Success",
"longMessage":"Request Completed Successfully.",
"status":20001
};
json = serializeJSON(a);
b = deserializeJSON(json);
writeDump(b);
</cfscript>
You can try it here:
http://trycf.com/gist/70b86fbb57f752125f35/acf?theme=monokai
(Too long for comments)
my code is producing the correct outcome is the deserializeJSON() that
is causing the issue.
Not quite. The JSON value is correct, but the serialization omits the surrounding quotes. That means the value will be handled as a numeric type during deserialization, causing the issue you observed. Unless you can force the serialization to treat the value as a string, the deserialized result will always be wrong. As Carl Von Stetten already mentioned, it is a bug. Jedihomer Townend's answer of appending a space character is probably the simplest work-around.
Longer answer:
Despite the improvements in CF11's JSON handling, CF is still a little too "helpful" ... As you noted, CF detects the value is numeric when serializing and omits the surrounding quotes. Consequently marking the value type as numeric.
{..."businessUnitValidList":2003051509034372557922 }
That all sounds great, until you try and deserialize. If the value was enclosed in quotes, it would be handled as a string, and the original value preserved. Unfortunately, without the quotes it is considered numeric, which means CF must stuff the value into one of its two numeric data types:
Real or floating point number, ie java.lang.Double or
32 bit Integer, ie java.lang.Integer
The maximum value of an Integer is 2147483647. Obviously your number is too large for that, so CF converts it into a java.lang.Double instead. That is a problem for two reasons. First, Double is an approximate type. Second, according to the rules of that class, scientific notation may be used when representing the number as a String, ie when the variable is displayed with cfoutput or cfdump. That is why the deserialized result looks different than what you were expecting. Unless you can force it to be treated as a string when serialized, the deserialized result will always be wrong.
In fairness, CF11 does contain a number improvements for JSON handling. Unfortunately most of them revolve around cfc's and query objects. Given your current structure, it won't quite work. However, if you were able to use a single query object you could resolve the issue by with the help of the new application level setting this.serialization.serializeQueryAs = "struct";. It forces a more sensible format for serialized queries than in earlier versions. Since CF11 respects column data types when serializing, the value would be preserved if the column data type is BIGDECIMAL, or you cast it as a VARCHAR. Unfortunately, CF still upper cases query column names, but the base values are preserved.
Result:
[ { "BUSINESSUNITVALIDLIST" : "2003051509034372557922",
"LONGMESSAGE" : "Request Completed Successfully.",
"SHORTMESSAGE" : "Success",
"STATUS" : 20001
} ]
Code:
qry = queryNew("");
queryAddColumn(qry, "businessUnitValidList", "varchar", ["2003051509034372557922"]);
queryAddColumn(qry, "shortMessage", "varchar", ["Success"]);
queryAddColumn(qry, "longMessage", "varchar", ["Request Completed Successfully."]);
queryAddColumn(qry, "status", "integer", [20001]);
json = serializeJSON(qry);
writeDump(deserializeJSON(json));
CF11 also introduced custom serializers/deserializers, which might work here. Though it is probably overkill for this specific task.
Having said all that, again the simplest option is to use the "append a non-numeric character" hack. Well .. either that or switch to a custom library which may do a more consistent job with JSON handling ;-)
Side Note / Efficiency:
Unless there is a specific reason you must execute a query within a loop, there are likely more efficient options (dbms specific, which you did not mention). Also, do not forget to use cfqueryparam on all variable query parameters. Among it is many benefits is boosting performance when the same query is executed multiple times - such as inside a loop.
In java we have BigInteger data type to store big values. In Coldfusion we can cast by using JavaCast to integer, long and double. But the problem with this is that even with 'long' datatype can only store 19 digits.
And by converting number to string it may be problematic to perform mathematical operations. Here we can use precisionEvaluate() while performing mathematical operations.
PrecisionEvaluate function lets you calculate arbitrarily long decimal
(BigDecimal precision) values. BigDecimal precision arithmetic accepts
and generates decimal numbers of any length.
In this example you can use like this :
<cfset ResponseStruct['BusinessUnitCodes']['businessUnitMixResponse']['businessUnitInValidList'] = "#precisionEvaluate(businessUnitInValidList)#">

Why does d3.select() return array of array?

I recently started using d3.js to write some scripts to manipulate SVGs. So most of the time I refer d3 documentation and find the solution. However I cannot understand why d3.select function return array of arrays. For example let's say i have an SVG element and if I do d3.select("svg"), it returns [[svg]] so I have to do d3.select("svg")[0]. The documentation says
One nuance is that selections are grouped: rather than a one-dimensional array, each
selection is an array of arrays of elements. This preserves the
hierarchical structure of subselections
Then says we can ignore it most of the time.
Why does it return array of array ?
What does
This preserves the hierarchical structure of subselections
mean?
Thanks in advance.
You shouldn't need to know or care how the object d3.select returns is structured internally. All you need to know is which methods are accessible in that object, which is what the documentation describes.
Say you have this document:
<div>
<span>1</span>
<span>2</span>
</div>
<div>
<span>3</span>
<span>4</span>
</div>
If you select all <div> elements with d3.selectAll
var div = d3.selectAll("div");
the div is a d3 selection object of size 2, one for each <div> element in the document.
But if you now generate a subselection from this selection object
var span = div.selectAll("span");
a search is made for matching elements within each element in the div selection, and the structure is preserved -- i.e., the span selection will contain the same number of elements as the div selection it was based on, and each of these will consist of a selection of elements found in that element.
So in this case, span will contain two selections (first <div> and second <div>), each of which will contain two elements(1 and 2 in the first, 3 and 4 in the second).
As for select, it is the same as selectAll except it stops after finding one match; its return is structured exactly the same way, however.
Demo

Using greater than logical expression in rendered attribute

I have an outputText field for which I write a condition in the rendered attribute. The condition is for comparing the length of the string with some numeric value.
<h:outputText id="emailaddress"
value ="#{subsAlertsHelper.personEmail.substring(0,20)}"
rendered="#{subsAlertsHelper.personEmail.length() >20}" />
If I use == or != in rendered it is working fine. But for greaterthan and lessthan it is not giving the output. What could be the reason for that?
You have to use gt and lt operators.
Check out JavaServer Faces Expression Language Intro from Sun/Oracle. Precisely the Operators section.
rendered only accepts EL expression.
subsAlertsHelper.personEmail.length() is incorrect.
On the personEmail object, add a method getLength() witch returns the length
public int getLength(){ return this. length();}
Modify :
rendered="#{subsAlertsHelper.personEmail.length >20}"

Resources