2

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.

Sam Holder
  • 32,535
  • 13
  • 101
  • 181
regisbsb
  • 3,664
  • 2
  • 35
  • 41

2 Answers2

1

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)

Sam Holder
  • 32,535
  • 13
  • 101
  • 181
  • I know. Page objects don't mix very well with those script like scenarios but sometimes is all we have. I've used a similar approach to what you've said. – regisbsb Jul 29 '15 at 14:53
0

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)

Tz_
  • 2,949
  • 18
  • 13