Reuse steps of Specflow when using Page Objects pattern - specflow

I am using Specflow with page objects and I have a lot of scenarios which are very similar. For example:
Given I view the 'page1'
When I click 'link1'
Then I should be on 'page2'
Given I view the 'page1'
When I click 'link2'
Then I should be on 'page3'
I am struggling to see how I could have one step binding for the "When I click..." step. If I follow the page objects pattern I should always return the specific page object that I am navigated to in the "Then I should..." step.
I have a base step definition class which contains a property which stores the current page object.
public class BaseStep : Steps
{
protected RemoteWebDriver Driver {
get
{
return ScenarioContext.Current.Get<RemoteWebDriver>();
}
set
{
ScenarioContext.Current.Set(value);
}
}
protected BasePageObject CurrentPageObject
{
get
{
return ScenarioContext.Current.Get<BasePageObject>();
}
set
{
ScenarioContext.Current.Set(value);
}
}
}
I do not want to write one step definition for each scenario as it is reusing a lot of code that I would rather be in a single method. So how can I reuse the step definitions and still use the page object pattern?
Thanks.

you can do this by exposing a property on your base page object which allows iteration of all controls on the current page (via reflection probably, but how you implement this is irrelevant as long as it works).
Once you have this then you can implement the step by calling this property looking for the link with the name given in the step ('link1' or 'link2') and then clicking this.
Whilst this will work, I would recommend that you should try and refrain from making your scenarios so specific to the implementation. Rather than "when I click 'link1'" it is better to have something that is more descriptive of the intention then the implmentation, "when I go to the basket" or "when I navigate to my account details". This isn't so reusable, but it is also resistent to refactoring of your design, and allows your steps to be reused for different devices when 'clicking' a link doesn't make sense (like touch devices)

I would be also very interested in the opinion and practices of others, but here are my thoughts.
If you go for a generic "When I click '([^']*)'" binding, you have not much information in the generic When what the current scenario is about. Still you can try to "wait" for the next page loaded, and you can check the (IWebDriver) Url to figure out where you are (according to the browser). You will need a mapping between the Url and your page objects to be able to select the current page object appropriately. You can build up a mapping manually for this purpose, you can use some conventions, or you can use other existing "mapping information" like the ASP.NET routing or a site map, or most probably some mixture of these. ;)
Another possibility is to defer the evaluation of the current url to the Then, but in this case probably the CurrentPageObject property getter should encapsulate this. What I mean is that the value of the property should not depend on whether you "call" a certain Then or not.
I tried a slightly different approach in one of my last projects. I wrote more specific When statements for my scenarios, so instead of "When I click 'Search'", "When I click 'Order'" or "When I click 'Confirm'" I had "When I fire the search with the parameters filled in", "When I order the items selected", or "When I confirm the order". Since these statements described a concrete action, I delegated them to the current page object (casted to the concrete page in question), where the page object had concrete methods for these actions. The implementation not only "clicked" the appropriate button (base functionality), but it also waited for the page load and set the current page object appropriately. In such concrete cases it was either obvious what the "next" current page object is, or I could more or less easily check what had happened, if there were more possible outcomes. The price I paid was that it was not just a single generic When step definition for clicking, the benefit (besides the one explained above) was that the phrasing of the scenarios was more focused on the user intention and not on the concrete UI-control-level interaction (performing an action vs. clicking something)

Related

Named (map) constructors do not work in grails.gsp.PageRenderer

When I use a map constructor like:
Person p = new Person(name: "Bob")
through something that is called via a grails.gsp.PageRenderer, the field values are not populated. When I use an empty constructor and then set the fields individually like:
Person p = new Person()
p.name = "Bob"
it succeeds. When I use the map constructor via a render call, it also succeeds.
Any ideas as to why this is the case?
Sample project is here in case anyone wants to dig deeper: https://github.com/danduke/constructor-test/
Actual use case, as requested by Jeff below:
I have a computationally expensive view to render. Essentially it's a multi-thousand page (when PDF'd) view of some data.
This view can be broken into smaller pieces, and I can reliably determine when each has changed.
I render one piece at a time, submitting each piece to a fixed size thread pool to avoid overloading the system. I left this out of the example project, as it has no bearing on the results.
I cache the rendered results and evict them by key when data in that portion of the view has changed. This is why I am using a page renderer.
Each template used may make use of various tag libraries.
Some tag libraries need to load data from other applications in order to display things properly (actual use case: loading preferences from a shared repository for whether particular items are enabled in the view)
When loaded, these items need to be turned into an object. In my case, it's a GORM object. This is why I am creating a new object at all.
There are quite a few opportunities for improvement in my actual use case, and I'm open to suggestions on that. However, the simplest possible (for me) demonstration of the problem still does suggest that there's a problem. I'm curious whether it should be possible to use map constructors in something called from a PageRenderer at all. I'm surprised that it doesn't work, and it feels like a bug, but obviously a very precise and edge case one.
"Technically it is a bug" (which is the best kind of bug!), and has been reported here: https://github.com/grails/grails-core/issues/11870
I'll update this if/when additional information is available.

When is localization (or lack of) a bad thing?

The following code returns a message which states whether the input value is a palindrome:
(for the sake of this post, the syntax isn't important, or written in any particular language)
function isPalindrome(
value: string,
successMessage: string = "Is palindrome",
failureMessage: string = "Is not palindrome"): string {
return value.reverse() == value ? successMessage : failureMessage;
}
Notice in the code above, the default messages are written in English, however as they are supplied as parameters, this method could easily be localized, and because the method has default values for the messages, this doesn't force the developer to provide them; for example:
isPalindrome("level") // returns "Is palindrome"
However we can demonstrate localization; for example, in spanish:
isPalindrome("level", "es palíndromo", "no es palíndromo") // returns "es palíndromo"
This got me thinking, when should code be designed with localization in mind?
Another example would be with exceptions; for example:
class PalindromeException : Exception("Is not a palindrome")
function validatePalindrome(value: string): void {
if (value.reverse() != value) {
throw PalindromeException();
}
}
Notice in this example that there is no way to localize the message in the exception. I know this could easily be fixed using the same principles in the first example, but it has been purposefully designed to demonstrate a lack of globalization.
Therefore, when should globalization be applied to code, so that it may be localized? When does it matter, and when does it not?
I believe, there's no ideal answer - everything depends on your architecture and use-cases.
However, I would suggest the following patterns:
All log messages (both server and client) should be in English
All error API responses should always provide a description in English and a unique error code which you can translate into a friendly message on the client side
In order to provide a good UX, all client messages should be in a user's language
In general, it's a good practice to have all technical data (logs, errors, etc) in English. All user-facing data has to be understandable for a user.
It strongly depends on your use-case. I would recommend to localise messages, that are displayed in a frontend, right away. My experience is, it's very costly to do it later. For debugging or monitoring messages I probably would do it just in english, 'cause most of developers are able to read english messages.
The only place where localization should take place is in the UI. If you’re sticking to the MVC principle of separation of concerns (or something similar like MVP or such), then the localization happens exclusively in the View part. Your isPalindrome function sounds more like business logic belonging to the Model part and should therefore not be concerned with i18n at all. Neither should exceptions worry about it, since no exception should ever be printed to the UI as is (except to provide debugging information, which doesn’t need to be/shouldn’t be localized).
Your function should only return true or false, and an entirely separate UI part should translate that into something user facing, potentially localizing it in the process. Same with the exception, it should be caught by something which loads an appropriately localized UI explaining the issue to the user.
All labels needs to be translated.
For this definition, text is an information being read by end user. In that context, a label is a piece of text which at the same time is not user input or user data.
To give an example, in an 'Save as' dialog the file name would be user input, the file content user data and the Save and Cancel labels on the two buttons would be the labels (and therefore in need of an translation).
Given this definition, the rule is as follows:
Only user interface code needs to translate and it translates all labels. On the opposite, business logic code not directly facing end users (such as libraries or backend services) shall not translate at all. Further, neither the business logic implementation nor the business logic API handles text other then user input or user data.
The rule thus also implicates clean separation of business logic code from user interface code. That comes very handy for testing.
For the palindrome example, the function would be business logic, and it would not return a text but something more suitable e.g. an boolean or enum. The user interface code would then evaluate the return and translate it appropriately. The same applies to the exception.

How to bind from DataTemplate to Page's DataContext?

I've got a page where a DataTemplate is being used to bind to the model for that content, e.g.:
<DataTemplate x:DataType="models:MyDataType">
... content ...
</DataTemplate>
In that content, I need to be able to bind a Click event. I need that click event to exist in the view model that is set as the page's DataContext:
<Page.DataContext>
<vm:MyViewModel x:Name="ViewModel">
</Page.DataContext>
but I'm really struggling with getting it to compile. Every approach I try results in the compilation error "Object reference not set to an instance of an object".
I know I can't use x:Bind because that will bind to the DataTemplate's DataContext, so I've been trying to use Binding and, based on other SO answers I've read, it seems like the answer should be:
Click="{Binding DataContext.Button_Click, ElementName=Page}"
where Page is defined as the x:Name for the Page. I've tried removing DataContext. I've tried adding ViewModel.
What am I misunderstanding? Is it not possible to do what I want to do? I've tried using code-behind instead but I'm using Template 10 and that pushes almost everything onto the view model, which makes it harder for me to access things like the navigation service from code-behind.
tl;dr; use Messaging.
#justinXL is right, 'ElementName' can work. But is it best?
The problem you are trying to solve has already been solved with messaging. Most MVVM implementations include a messaging solution. Prism uses PubSubEvents; MVVM Light has its own messenger. There are others, too.
The idea is that an outside class, typically described as a message aggregator, is responsible for statelessly receiving and multicasting messages. This means you need to have a reference to the aggregator but not a reference to the sender. It’s beautiful.
For example
A common use case might be a mail client and how the data template of a message in the list would include a trash/delete button. When you click that button, what should be called? With messaging, you handle the button_press in the model and send/publish a message (one that passes the item).
The hosting view-model has subscribed to the aggregator and is listening for a specific message, the Delete message that we just sent. Upon receipt, it removes it from the list and begins the process to delete it from cache/database, or whatever – including prompting the user with “Are you sure?”
This means all your data binding in your data template is local, and does NOT extend outside its local scope. Why does this matter? Because if you use Element Binding to reach the hosting page, it means you cannot 1) move this template to a resource dictionary or 2) reuse this template.
There are two other reasons.
you cannot use compiled x:Bind to do this because it already limits use of this painful binding approach – this matters because a data template is typically in a list, and performance should always be prioritized, and
It adds considerable complexity.
Complexity?
I am a big fan of sophisticated solutions. I think they are rare and are the trademark of truly smart developers. I love looking at such code/solutions. Complex is not the same as sophisticated. When it comes to complexity, I am not a fan. Data binding is already difficult to wrap your head around; multi-sourcing your data binding across scope boundaries is pure complexity.
That’s what I think.
Your binding expression is correct, except it won't work with a Button_Click event handler. You will need an ICommand defined in your page's ViewModel.
Since you are using Template10, you should be able to create a DelegateCommand called ClickCommand like this
private DelegateCommand<MyDataType> _clickCommand;
public DelegateCommand<MyDataType> ClickCommand
{
get
{
_clickCommand = _clickCommand ?? new DelegateCommand<<MyDataType>>((model) =>
{
// put your logic here.
});
return _clickCommand;
}
}
And the binding will be updated to
<Button Command="{Binding DataContext.ClickCommand, ElementName=Page}" CommandParameter="{x:Bind}" />
Note I have also added a CommandParameter binding to the button as you might want to know which MyDataType instance is associated with the clicked button.

Where to put ParseUrl() or similar function that works against a datastore, in ASP.NET MVC?

If you were to code a function/method that would, for entered string or slug (for instance in Create or Edit view), go into datastore and check whether that string or slug exists and in this case create a link to it, where would you put it?
For instance, we have a "Link" textbox on our Create or Edit form. I have a jQuery autocomplete wired to it, which retrieves existing Page slugs. If a user decides to select one of them, we would create a link that points to the content within our site, based on the Page controller, like this:
~/Page/Display/some-slug
or just
~/Page/some-slug
If, however, user decides not to select anything and inputs for instance www.google.com, we catch it in our ParseUrl(), format it with http://... etc. and store it like that.
The code for the function is no problem and I have it working currently in a Model Binder. However, due to strange, confusing and opposing practices with DI in Model Binders I would like to move it somewhere else. Another reason would be to remove dataccess code from Model Binders.
The question is - where to move such funcionality? If possible, I would like to avoid repeating ParseUrl() calls across various controller actions.
1) Implement it so it makes sense to you and your team.
-or-
2) Leave it where it is because its already working.
Is moving it going to make your app better, will your customers be happier, deadlines met faster?
There is no magic Asp.net MVC thunder-god that descends from the heavens to smite you if you dare use the wrong extensibility point. Nobody is going to call you an idiot. People may disagree, but that happens. Its ok to "go for it" and get things done before being architecturally pure.
"However, due to strange, confusing and opposing practices with DI in Model Binders"
What does that even mean?

How much logic do you put in views?

I am currently unconfident, if I can put a "if/else"-construct into my view?
How much logic do you put in your views?
My dilemma:
I am rendering a navigation. So, I have to differ between the current/active menu item and the rest. The current menu item gets a special css class. I don't know how to handle this in a better way than using if-else.
If you are doing MVC (hopefully you do), than the question is "Do I put the logic in the view or the controller?". I use a simple rule to find out the answer of that:
What if my view was not HTML, but an XML document?
If I will need this logic in both circumstances - its place is in the controller. If not - it's in the view.
In good MVC design you should be able to swap the views without touching the controller.
As much as is necessary to display the information. Just remember that the view is just a window into the internal state of the program. If you stripped the view layer completely away, the program should still be able to operate as usual, just without being able to see what it's doing.
edit: re your navigation, that seems like an okay use of an if statement. The information about which is active is still coming from the model, you're simply using the if statement to decide how to display it. You might consider a little bit about how you're rendering your navigation: is the information about which navigation items available, and which to render living in your view or your model?
One way you might choose to approach the situation is to have the model give you a list of navigation items, along with which one is active, and program the view to know how to generate appropriate HTML from that. That code might contain precisely one if statement total. (instead of one for each nav item).
I wouldn't worry about putting an if statement in a view. In fact, I think there's a bit too much hand-wringing (in general) about responsibilities in these kinds of situations.
If you make your views too dumb then your model can become too view-sentric (tightly coupled).
IMHO a view can do what it likes but the guiding principle should be: where does it get its information from? If the answer is "the model" then use as much logic as you like.
An "if/else" construct is fine if the view is alternating modes, e.g. formatting a U.S. address vs. a foreign address in an order screen.
However, any logic that you place into a view should not alter the model.
Add this helper to your application_helpers.rb It will surround your links with <li> and <li class="active"> if the link is the current page.
Use it in place of a link_to.
link_to 'home', root_url, optional_condition_argument_goes_here
def active_link_to(text, url, condition = nil)
if condition.nil? and String === url
condition = url == request.path
end
content_tag :li, link_to(text, url), :class => (condition && 'active')
end
(Courtesy of Mislav)
I might put if-else in a view. In most cases not. The real question in my mind is whether the logic could go anywhere else without being messier.
I tend to avoid putting control-flow logic in my views (ASP.NET MVC) except under circumstances where I may want a portion of the interface visible/not visible based on the presence or absence of data. In this case, it is view logic -- I'm determining the layout of the page, the elements of the page that are available, etc. I think that this is perfectly acceptable and preferable to having the controller determine this or multiplying views to account for minor variants. The controller needs to give the view enough information for it to be able to render the view and its variants as needed.
What I wouldn't put into the view is business logic that determines how to calculate something or whether to perform some action (except, perhaps, for role-based decisions -- these seem to crop up just about everywhere). Other than client-side validation, my business logic resides in the controller/model.
An example of where I might use if/then logic in a view is a view which displays events. In my app, events can have subevents, but subevents can't have further subevents: a two level hierarchy. On my display page, I have tabs for Details, Groups, Participants, and Subevents. These are the same for both events and subevents, with the exception of the Subevent tab. It shouldn't exist for a subevent. Rather than repeat myself by having two different views that are virtually identical except for that one tab, I've added a tiny amount of logic to the view to not render the Subevent tab if an event has none.
By the same token, I wouldn't go so far as to have a single "view" that uses logic to determine whether to show an overview or details or editing pane, etc. based on the value of some view data item. This seems an abuse of the single responsibility principle as applied to views. Each view should have a single-purpose, IMO.
Logic that is in the view should not be required to fully describe the current state of the model.
Said another way, logic in the view is acceptable if that logic is used to format or alter the visualization of the information. Logic in the view might also have a use in vetting data that is entered before taking the expense of transmitting that data to the controller (in a client/server or web application).
For instance, the view might include logic to split a list of items into multiple columns when the list is longer than N items. That split could be done in several different ways according to the exact nature of the view (e.g. http, mobile device, pdf, voice reader, Morris Code, etc, etc, ad nasium). The full view information might need to be paginated - and that can only be done in the view. Formatting logic should not ever be included in the controller or the model.
As a corner case, the view might include logic to check that a password entered for a new user meets the current security requirements (e.g. double entry of password matches; at least N characters long; does not include spaces or the "*" character; includes at least three of the following: lower case letters, upper case letters, numbers, symbols; is different than the last N passwords, no based on a dictionary word, etc, etc). Depending on the nature of the logic, vetting a password could be thought of as "formatting" or as "business logic". It might be that the check happens in two passes - one set of checks for formatting in the view, and another set of checks in the controller with info from the model (the last N passwords).

Resources