For Geb Page Object, when is the static content block initialized? - groovy

When following the geb page object pattern, it is encouraged to create a static block of values that represent the elements on the page you are attempting to interface with. It is also good to create an at checker. Here is an example:
class SomePage extends Page{
static at = {$(By.xpath("some header or something")).displayed}
static content = {
element1 {$(By.xpath("some xpath1"))}
element2 {$(By.xpath("some xpath2"))}
//so on and so forth
}
}
Now I think I know the answer this question already but could not find the docs to back it up. I am pretty sure that the static content block is initialized once the "at checker" is called from a test script, but I am not sure. If what I am suggesting is true then that would mean something like this:
class SomePage extends Page{
static at = {$(By.xpath("some header or something")).displayed}
def someString
static content = {
element1 {$(By.xpath("//*[contains(text(), ${someString}"))}
element2 {$(By.xpath("some xpath2"))}
//so on and so forth
}
def setSomeString(String x){
this.someString = x
}
}
would be impractical right, or maybe even impossible? This is because in order to call "setSomeString" you need to call the at checker to tell the script which class to reference for method and variable calls, but if you call the at checker that means the static content becomes initialized.
Furthermore, if a webpage has content that doesn't show up upon initial arrival to the webpage, then you would not be able to put that content into the static content block either, since the at checker should be called as soon as you arrive on said webPage.
I am simply looking to confirm or deny that this is the behavior of geb page object. and I would be happy to hear answers describing best practice given the above situation.
also if there is a way to re-initialize the content, I would like to know that too, but I figure there is not.

A content definition is evaluated every time the result of the definition is requested:
def somePage = to SomePage //at checker is executed but the defintion for element1 isn't
somePage.element1 // closure defined for element1 is executed
somePage.element1 // and here again
// many lines of code which trigger additional content to show up on the page
somePage.element1 // closure defined for element1 is executed again

Related

File reading in Kotlin without piggybacking off a button

I am coding a data class that is wanting to read a csv file to grab some information that is stored on the file. How ever, every way that I have tried to read the file will not work.
Here is what I have tried so far:
data class Bird(val birdNumIn: Int){
private var birdNum = birdNumIn
/**
* A function that searches the bird-data.csv file which is a list of birds to find the bird that was
* inputted into the class constructor and then add the values of the bird to the private variables.
*/
fun updateValues(){
var birdNumber = birdNum
var birdInfo: MutableList<String> = mutableListOf()
val minput = InputStreamReader(assets().open("bird-data.csv"), "UTF-8")
val reader = BufferedReader(minput)
}
How ever the assets().open() does not work. It returns an error of trying to open a file that does not exist, but the is in the assets folder, and the filename is spelt right.
I have tried many other methods on trying to read files, like using Java.io.File and using the path of the file.
If you would like to look at our whole project, please feel free to go to our github
What's the assets() function you're calling? This is just a bare data class, it has no connection to the Android environment it's running in, so unless you've injected an AssetManager instance (or a Context to pull it from) into your class, you can't access it.
You probably need to do this:
fun updateValues(context: Context){
val inputStream = context.assets.open("bird-data.csv")
val minput = InputStreamReader(inputStream, "UTF-8")
...
}
which requires your caller to have access to a Context.
Honestly from a quick look at your class, you might want to rework this. Instead of having a bunch of empty fields in your data class (which aren't part of the "data" by the way, only stuff in the constructor parameters is), and then having those updated later by the data class doing some IO, you might want to keep them as just basic stores of data, and create them when you read from your assets file.
So something like:
// all fixed values, initialised during construction
// Also you won't need to override toString now (unless you want to)
data class Bird(
val birdNum: Int
val nameOfBird: String
val birdFilePic: String
val birdFileSong: String
val alternativeName: String
val birdInfoFile: String
) { ... }
Then somewhere else
fun getBirbs(context: Context) {
// open CSV
// read the lines
val allBirds = lines.map {
// parse data for each bird, use it to construct a Bird object
}
}
or whatever you need to do, e.g. loading certain birds by ID.
That way your Bird class is just data and some functions/properties that work with it, it doesn't need a Context because it's not doing any I/O. Something else (that does have access to a Context) is responsible for loading your data and turning it into objects - deserialising it basically. And as soon as it's created, it's ready and initialised and immutable - you don't have to call update on it to get it actually initialised.
And if you ever wanted to do that a different way (e.g. loading a file from the internet) the data class wouldn't need to change, just the thing that does the loading. You could even have different loading classes! One that loads local data, one that fetches from the internet. The point is the separation of concerns, so it's possible to do this kind of thing because that functionality isn't baked into a class that's really about something else.
Up to you but just a thought! Especially if passing the context in like I suggested is a problem - that's a sign your design might need tweaking

Asp.Net MVC ValidationSummary HTML error message

I've been asked to include a link in an error message when the Email address for a registration is already in use.
The validation for this property is done with a IValidatableObject.Validate function on the model. My validate function looks like so...
Public Overridable Function Validate(validationContext As ValidationContext) As IEnumerable(Of ValidationResult) Implements IValidatableObject.Validate
Dim results = New List(Of ValidationResult)()
....
If Not EmailAvailable(Email) Then
results.Add(New ValidationResult("The email address is not available. Forgot Password?", {"Email"}))
End If
Return results
End Function
In my views, I'm using a custom "MyValidationSummary" extension function to format the errors nicely.
The extension function does this...
....
Dim ul = New TagBuilder("ul")
For Each key In helper.ViewData.ModelState.Keys
For Each e In helper.ViewData.ModelState(key).Errors
Dim li = New TagBuilder("li") With {
.InnerHtml = helper.Encode(e.ErrorMessage)
}
ul.InnerHtml += li.ToString()
Next
Next
container.InnerHtml += ul.ToString()
Return New MvcHtmlString(container.ToString())
I know I could just remove helper.Encode, and just output the message as raw html, but this feels a bit hacky.
I'm trying to find a nice way to be able to selectively include html in the messages, while still retaining the default behaviour of encoding plain text messages.
What I thought of doing, is create a custom ValidationResult class, which optionally would include a HTMLString property, so that I can, if I choose, include HTML in the messages.
I can do this, but I don't know if there is any way to get at this custom ValidationResult from MyValidationSummary.
update:
For the time being, I've just added a placeholder tag into the error message, which I then substitute with the actual link in my MyValidationSummary extension method. It's very hacky, but it will work until I've found a better way to do it.

Groovy Closure reuse vs rehydrate copy

In the DSL page of groovy they show this
def email(Closure cl) {
def email = new EmailSpec()
def code = cl.rehydrate(email, this, this)
code.resolveStrategy = Closure.DELEGATE_ONLY
code()
}
Why are they calling rehydrate instead of just assigning the delegate to the closure:
def email(Closure cl) {
def email = new EmailSpec()
cl.delegate = email
cl.resolveStrategy = Closure.DELEGATE_ONLY
cl()
}
In other words, why do we need a copy of the closure instead of reusing the one given. I don't necessarily see a problem with using rehydrate but I also don't see the need, which tells me there's something I'm not understanding
I imagine it returns a copy rather than reusing the same closure in order to stay idempotent/safe in case you still need a reference to the old closure.
As #tim_yates mentioned, the rehydrate method sets the delegate, owner, and thisObject, whereas your second example only sets the delegate. It's not that the rehydrate method does anything magical, it's just a convenience method so you don't have to set all three properties individually/line-by-line.
I also believe rehydrate is meant to work with its partner method dehydrate, which returns a copy of the closure with those three fields cleared (allowing rehydrate to easily re-set them).

Why does my Groovy AST transform insert null at the end of my method?

I have written an AST transform that creates a setter for a JPA mapped property (it both sets the local field and calls setOwner on the other end of the relationship):
private static void createSetter(FieldNode field) {
Parameter parameter = GeneralUtils.param(field.getType(), field.getName());
BlockStatement body = new BlockStatement();
body.addStatement(assignS(fieldX(field), varX(parameter)));
MethodCallExpression setterCall = callX(varX(parameter), "setOwner", varX("this", field.getDeclaringClass()));
setterCall.setType(ClassHelper.VOID_TYPE);
body.addStatement(stmt(setterCall));
MethodNode method = new MethodNode(setterName(field.getName()), ACC_PUBLIC, ClassHelper.VOID_TYPE, new Parameter[] {parameter}, ClassNode.EMPTY_ARRAY, body);
field.getDeclaringClass().addMethod(method);
}
This works, but the generated method has a strange null statement at the end as disassembled by JD-GUI (in addition to an odd local variable):
public void setMore(Simple_MoreStuff more) {
Simple_MoreStuff localSimple_MoreStuff = more;
this.more = localSimple_MoreStuff;
more.setOwner(this);
null;
}
It doesn't seem to affect the actual correctness, but it's odd, and it seems like a bug. In MethodCallExpression, I found this comment but don't know if it relates, since my method is in fact void (I explicitly set it above, and it makes no difference):
//TODO: set correct type here
// if setting type and a methodcall is the last expression in a method,
// then the method will return null if the method itself is not void too!
// (in bytecode after call: aconst_null, areturn)
Is there a way to keep the generated method from having the spurious null?
I have not looked at JD-GUI, so I cannot tell how capable this tool is in understanding bytecode, that does not come from Java. But in general disassemblers can only somewhat show what Java code in that case might look like, by no means it is supposed to show correct code from a non-Java language. So better do not expect correct Java code if you disassemble Groovy.
In this case I suspect that JD-GUI stumbles over a workaround we have not gotten rid of yet. In several cases we add at the method end dead code, the const_null, areturn you have noticed. We do this because of problems with the verifier if a bytecode label is used at the end of a method. And since the dead code does not influence correctness we are currently using this solution.

Xpage extlib Dialog keepComponents true and JSF component

i have a problem with the Dialog control from the Extention library:
I have created a java custom control wich searches some views, collects some data and displays it. This works nice if i place it on a XPage.
But i want to display the data in a Dialog so i used the Dialog control from the extention library. Using the Dialog control without any configuration also works fine but it takes some time for my control to search the views and display the data every time i open the dialog.So to reduce the waiting time for the user i wanted to use the option "keepComponents="true" from the Dialog control.
Now if i open the Dialog for the first time everything is perfekt but if i open it a secound time it displays the content from the first opening in addition to an error from my controlRenderer wich tells me that it could not get the viewName from the control. This error stacks up for every time i open and close the dialog.
I found a Post on OpenNtf from somebody who had the same issue with multiple content in his dialog when using this option but he didnt get any answers to his question.
Is this a bug of the component? Should i forget this option and cache my data in a bean? Why can't the renderer get the Viewname from the component?
The answer that follows assumes that the phrase "java custom control" in your question refers to a JSF component you developed; in XPages, the term "custom control" usually refers to an instance of a Custom Control design element, which is IBM's implementation of the JSF notion of "composite components".
You've stated that the component initially behaves as intended but fails on subsequent requests. This typically indicates that the restoreState and saveState methods of the component have not been properly implemented.
When the default serialization options are enabled for an application, all component state is written to disk at the end of each request, and read back into memory at the beginning of the next. These two operations are handled, respectively, by the saveState and restoreState methods of each component.
For example, suppose you defined a component for adding HTML canvas tags to an XPage, and decided to support the gesture and touch events associated with that element. So your component class would contain fields to store any code bound to those events:
private String ongesturechange;
private String ongestureend;
private String ongesturestart;
private String ontouchcancel;
private String ontouchend;
private String ontouchmove;
private String ontouchstart;
Each of those fields would typically then have an associated "getter" and "setter" method:
public String getOngesturechange() {
return getStringProperty("ongesturechange", this.ongesturechange);
}
public void setOngesturechange(String ongesturechange) {
this.ongesturechange = ongesturechange;
}
When an instance of that component is initialized, the "setter" method associated with each attribute that is defined for that component instance will be passed the value defined for that attribute. For the remainder of the initial page request, then, the private field for each defined attribute will store the value that was set. At the end of the request, the saveState method writes the values of these fields to disk. A typical saveState method looks similar to the following:
#Override
public Object saveState(FacesContext context) {
Object[] properties = new Object[8];
int idx = 0;
properties[idx++] = super.saveState(context);
properties[idx++] = this.ongesturechange;
properties[idx++] = this.ongestureend;
properties[idx++] = this.ongesturestart;
properties[idx++] = this.ontouchcancel;
properties[idx++] = this.ontouchend;
properties[idx++] = this.ontouchmove;
properties[idx++] = this.ontouchstart;
return properties;
}
The call to super.saveState() executes the same method, but using the version of the method defined in the parent class. So the on-disk representation of each component is essentially a nested array: each layer in the hierarchy stores all the properties it inherits from its parent class in the first element of the array, then stores all the properties that it defines in additional array elements.
When the component tree is restored on subsequent requests, each component uses its restoreState method to reconstitute the values of all its fields. A typical restoreState method looks similar to the following:
#Override
public void restoreState(FacesContext context, Object state) {
Object[] properties = (Object[]) state;
int idx = 0;
super.restoreState(context, properties[idx++]);
this.ongesturechange = ((String) properties[idx++]);
this.ongestureend = ((String) properties[idx++]);
this.ongesturestart = ((String) properties[idx++]);
this.ontouchcancel = ((String) properties[idx++]);
this.ontouchend = ((String) properties[idx++]);
this.ontouchmove = ((String) properties[idx++]);
this.ontouchstart = ((String) properties[idx++]);
}
This hierarchically reads the on-disk data back in: each class passes a set of properties to the parent class, then assigns the remaining array elements to the fields they were associated with when the component state was saved.
This process provides an easy way to maintain component state across requests -- each layer of inheritance need only concern itself with the new properties that layer defines -- but these state maintenance methods are easy to forget to implement. If either method is omitted from the component implementation, then the page "forgets" the property values on subsequent requests, because either they were never written to disk, or were not loaded back into memory, or both.
Assuming that this is the root cause of your problem, the reason the problem does not occur when the component is inside a dialog with the default (false) value for keepComponents is because the default dialog behavior is to remove its children from the component tree entirely when the dialog is closed. This behavior is for performance reasons: there's theoretically no benefit to be gained from storing a server-side representation of components that only exist inside a dialog that the user is not currently interacting with. When the dialog is opened again, a new instance of each child component is created using the original property values. In this scenario, it wouldn't matter that your component isn't saving its state, because each time it's used, a new instance is created. But if the dialog is told to keep its children in the component tree, now the component must properly maintain its own state... otherwise its property values are discarded at the end of each request and subsequent requests are unaware of the previous values.
In summary, yes, the data you're displaying should be cached in a bean (or data source) if the data is unlikely to change enough between requests to justify obtaining the data again during every single event. But the reason for the specific behavior you're describing is most likely because your component implementation is not properly maintaining its own state.

Resources