selenium Page factory handle different elements for same page for different users - selenium

I have a simple question. I 'm sure many of us might have got into the same situation. I am using page object pattern. Below are the steps i do along the navigation.
Login to my application as one type of user.
Click some link to go form page.
On form page , fills the fields and submit
Logout
On 3) the form object page shows some different input fields depending on the type of the user, which i need to interact with. So how do i deal it within the same page object. Has anybody got into the same situation and have found some decent way of doing this ?

I know it a simple automation script not a Java project where we should be using all oops concepts but still I would go with the following:
Create a parent page class containing the common WebElements and methods.
Create child classes with elements and methods specific to that customer.
In the test, pass a parameter which specifies the type of customer and call the appropriate child class.
If you don't want any of this inheritance stuff, you can also try the following.
Create a page class with elements for all types of customers.
Create generic methods which can take a parameter customerType and perform operations like if customerType==1 do these operations else do these.
Another solution which popped up in my mind, assuming that all fields for a particular customer are mandatory, is as follows.
Create a common class for all elements.
Create a generic method in the page class which follows the condition, if this element is present then enter value.

If you understand the concept of Page object model then this questions will be more clear to you. Yes, inheritance is a big factor here. I suggest you read through this to see how a real page object model should work. And, solution of #3 question is as simple as UI mapping. Something like
#FindBy(how = How.NAME, using = "q")
private WebElement searchBox;
for each elements or similar implementation.
For a complete page object you should map all the elements not depending on the users. The reason being, every time you call that class it will be instantiated and all the mapped elements as well. There is no need of dynamically load the elements If any elements are not used or hidden on the page those will be available and you will not be using them anyway

Related

Vaadin 7 - Set and get attributes into VaadinSession

I'm currently using Vaadin 7 for creating a RIA and I'm designing the Login functionality.
The application design is simple:
A UI class performs navigation beetwen different View classes. In particular, the first displayed View is a LoginView class and after a user has been authenticated the UI class redirects the user towards a MainView.
After authentication I'd like to set User data (eg name and surname) into the session and display it always (no matter what specific view) on the top right corner of the Web Application.
As a begginner I read the Vaadin Book and I firstly used the scheme illustrated in chapter 11th https://vaadin.com/book/-/page/advanced.global.html, but it doesn't seem to work as expected, probably because I'm using View navigation scheme.
So I use the following approach:
Once authentication is correctly completed LoginView tries to store user data as a VaadinSession attribute with the following code:
VaadinSession.getCurrent().setAttribute("name", name);
then UI navigates to MainView and tries to get the name of the user with:
VaadinSession.getCurrent().getAttribute("name");
but it gets a null value.
Does anyone know why? I appreciate any help.
Thank you.
I would suggest storing the values on the HTTP session instead.
VaadinServletService.getCurrentServletRequest().getSession().setAttribute("name", name);
and
VaadinServletService.getCurrentServletRequest().getSession().getAttribute("name");
Use the #PreserveOnRefresh annotation on main class which is extends the UI.
Then you can store variables data in the main class.
You can give it from anywhere (in any View) with ((MyUIClass)UI.getCurrent()).getSomeVariable method expression.
I have a guess as to why you get your null value. In most tutorials of modern Vaadin, the navigation pages are created first-thing in the UI as objects. If one of these views instantiated in this process is the MainView. If the label displaying the name sets the String in the constructor of the class, the line:
label.setValue(VaadinSession.getCurrent().setAttribute("name", name)); will be null is the attribute has not been set by the login function yet.
You need to either update the label showing the user string in the #override enter() function, or handle it otherwise.

Get ancestor object of un-saved object in Hobo

I'm working on a Hobo app trying to tie together a few models properly.
Activity objects have many Page children. They also have many DataSet children.
Page objects have several different kinds of children. We'll talk about Widget children, but there are several types with the same issue. An instance of a Widget belongs to a Page but also has a belongs_to relationship with a DataSet. Here's the important point: the DataSet must belong to the containing Activity. So for any given #widget:
#widget.page.activity === #widget.data_set.activity
It's easy enough to enforce this constraint in the model with a validation on save. The trick is presenting, within the Widget's form, a select menu of available DataSets which only contains DataSets for the current Activity
I was able to get this working for existing objects using a tag like this:
<data_set-tag: options="&DataSet.activity_is(&this.page.activity)" />
However, for a new Widget, this fails messily, because either &this or &this.page is not yet set. Even for a route which contains the page ID, like /pages/:page_id/widgets/new, I'm not really able to get an Activity to scope the list of DataSets with.
If this was proper Rails, I'd get in to the relevant controller method and make the Activity available to the view as #activity or something of the sort, but in Hobo the controllers seems to be 95% Magicâ„¢ and I don't know where to start. The knowledge of which Activity is current must be in there somewhere; how do I get it out?
This is Hobo 1.3.x on Rails 3.0.x.
ETA: The code producing the errors is in the form tag for Widget, like so:
<extend tag="form" for="Widget">
<old-form merge>
<field-list: fields="&this.field_order">
<data_set-tag: options="&DataSet.activity_is(&this.page.activity)" />
</field-list>
</old-form>
</extend>
As I said above, this works for editing existing Widgets, but not new Widgets; the error is undefined method 'page' for nil:NilClass. Bryan Larsen's answer seems to suggest that &this.page should not be null.
it looks like you tried to post this question to the Hobo Users mailing list -- I got a moderation message, but it doesn't appear that your post got posted, nor can I find it to let it through. Please try reposting it, there are several helpful people on the list that don't monitor the Hobo tag here.
In Hobo 1.3, the new action doesn't support part AJAX, so there really isn't much magic. You can just replace the action with your own:
def new_for_page
#activity = Activity.find(...)
#page = Page.find(params[:page_id])
#widget = #page.widgets.new
end
There is a little bit of magic referenced above: if you're in WidgetsController, assigning to #widget will also assign to this.
But as you said, the knowledge is obviously in there somewhere, and your custom controller action shouldn't be necessary.
This statement seems wrong: However, for a new Widget, this fails messily, because either &this or &this.page is not yet set.
It looks like you're properly using owner actions. /pages/:page_id/widgets/new is the route. In widgets_controller it's the new_for_page action. In a new or new_for action, this is set to an unsaved version of the object. In your action, it should have been created with the equivalent of Page.find(params[:page]).widgets.new. In other words, both this and this.page should be populated.
I'm sure you didn't make your statement up out of thin air, so there's probably something else going on.
In the end, it turned out to be syntax. Instead of
<data_set-tag: options="&DataSet.activity_is(&this.page.activity)" />
I needed
<data_set-tag: options="&DataSet.activity_is(#this.page.activity)" />
(note the #).
We actually made this into a helper method, so the final code is
<data_set-tag: options="&DataSet.activity_is(activity_for(#this))" />

Sunspot searches for Rails' Single Table Inheritance

I have a Rails app with the Content model. The Content model has numerous STI children models, such as Announcement, Story, FAQ, etc. I need to be able to query Solr via Sunspot for each of the children independently and as a group.
This is the present implementation of Sunspot search in the Content model. It sets defaults for hidden and published, so only active Content is returned by Solr and accepts a block to allow farther search params:
def self.search_for(&blk)
search = Sunspot.new_search(Content)
search.build(&blk)
search.build do
with :hidden, false
with(:published_at).less_than Time.now
end
search.execute
search
end
This method works perfectly for Content and will return results for Content and all the children Models. I am not particular thrilled with the name of the method, search_for, but can't think of anything better.
I need to be able to search by child Model, i.e. Announcement.search_for(). I do not want to have this method pasted into the ~10 child Models, since the defaults are going to change in the near future. What I would like is have each of the children models inherit this method, but search for the child's class, not Content (e.g. Announcement would search by Sunspot.new_search(Announcement)).
Is there are way to reflect the class of a class method or does this method have to be dynamically generated at runtime to pre-define the calling class?
Pretty easy, just pass the instance type rather than Content. Change first line of the function to:
search = Sunspot.new_search(self)
Where self will hold Content if you invoke the method by Content.search_for and Announcement if invoked by Announcement.search_for. That's it!

Basepage handling events with two different types of controls

My problem is thus...
I have 4 pages which all essentially do the same thing, that is to value a specific vehicle based on the information entered, each of these pages is over 3.5k lines in the code behind.
The pages need to remain separate to allow for some minor differences between the way in which each page is accessed and to allow for future changes, however they all use the same IDs for controls so I saw no reason why I couldn't move the event handlers to the base page along with primary functions, this would allow rapid addition of future pages just by referencing the base page and setting any in page overrides that I need.
So the actual problem is that I am defining the controls as public in the base page e.g.
"Public WithEvents lstCAPManufacturers As FLHighComboBox"
Now this is fine from 2 of the pages as they use our own user control FLHighComboBox, the problem arises when called from the other 2 pages which use standard .Net dropdowns and the public declaration dies. The same thing is occurring image buttons in one page which are standard buttons in the others, and .Net textboxes in one page which are (Telerik) RadTextBoxes in others.
I did consider declaring all controls of this type as objects, and then casting them to the appropriate control in a function called on page load, however this just causes masses of compilation errors and I am unable to access properties and methods for them because they are already defined as type Object.
So I'm really after suggestions for how I can make this kind of thing work, or if not how to make this work, what I should be doing instead.
Thank you.
Added custom handlers on page load for the controls that needed them and cast the others to their type on page load for those that didn't need handlers.

Need to access the Page object in Global.asax in the PreRequestHandlerExecute

I have a huge website (containing around 5000+) pages. There is a theme functionality in the website where user can choose different colors for their profile. Now i want to use the ASP.net theme feature and put different CSS (for different colors) in the theme folder and in Global.asax i want check the user theme and render appropriate link element with the css. But my problem is, i am not able to access the Page element for adding the link in the page.
Here is my code
Dim page As System.Web.UI.Page = TryCast(System.Web.HttpContext.Current.Handler,System.Web.UI.Page)
page.StyleSheetTheme = "Black"
But when i run this code I get a Null reference error.
P.s : My application is very huge so its not possible to have a master page or a base class and inherit it in every page.
Please suggest.
The page is not available in PreRequestExecute. This function is called before asp.net steps in to handle things, and asp.net is responsible for the page. Think of PreRequestExecute as being earlier in the scheme of things, like when IIS is first trying to figure out what to do with this thing it has, the thing is not even a page yet.
You might want to look into some of the other events that you can hook, there are events that would take place after the page has loaded that may allow you to do what you are suggesting.
Rather than going into global.asax for this, consider using master pages. One possibility is to have nested master pages, where the first master page sets up overall layout, and the nested master handles the theme. (Or one of several nested master pages, all referencing the same top-level master page). If necessary, you can use the PreInit event in the page to change master pages, and select the master that matches your theme selection.
You can centralize this function by having your own class that inherits System.Web.UI.Page, and have all your own pages inherit this new class. Handle the PreInit event there. (As well as other useful functions, like page-level handling of unhandled exceptions, general security issues, etc.
EDITED TO ADD: As #aepheus correctly notes, the page hasn't been instantiated at the PreRequestHandlerExecute event. So there's no page class you can access.